Bug 422538. Import libfishsound

This commit is contained in:
Xiph contributors (see /modules/libfishsound/AUTHORS), plus Chris Double 2008-07-29 23:43:24 -07:00
parent 66e5749786
commit c38cc109bc
33 changed files with 6490 additions and 0 deletions

View File

@ -0,0 +1,22 @@
Conrad Parker <conrad@metadecks.org>
- Design, implementation.
- Vorbis, Speex support
Tobias Gehrig
- FLAC support
Silvia Pfeiffer <silvia@annodex.net>
- MS Windows porting, general packaging.
Zentaro Kavanagh <ogg@illiminable.com>
- Windows porting and packaging.
based on code from:
libvorbis, by Monty <monty@xiph.org>, Xiph.org Foundation.
libspeex, by Jean-Marc Valin <jean-marc.valin@hermes.usherb.ca>,
Xiph.Org Foundation
libFLAC, by Josh Coalson, Xiph.Org Foundation.

View File

@ -0,0 +1,29 @@
Copyright (C) 2003 CSIRO Australia
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 name of the CSIRO nor the names of its
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 ORGANISATION 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.

View File

@ -0,0 +1,83 @@
2007-01-12 Thomas Vander Stichele <thomas at apestaart dot org>
* Makefile.am:
dist m4 macro
* include/fishsound/Makefile.am:
fix include directory when overriding includedir
2005-06-13 Thomas Vander Stichele <thomas at apestaart dot org>
* autogen.sh:
* m4/as-ac-expand.m4:
add m4 dir and use it
add an expand macro
* configure.ac:
uniformize configure's output across the annodex stack
Thu Jan 13 17:58:45 EST 2005 Conrad Parker <conrad@metadecks.org>
* added liboil support from David Schleef <ds@schleef.org>
Thu Jun 24 18:48:46 EST 2004 Conrad Parker <conrad@metadecks.org>
* Version 0.6.3
Bug fixes:
* non-interleaved Speex encoding re-written and tested
* memory leak in comments API closed
Tests and examples:
* new examples fishsound-encdec and fishsound-decenc to trial
encode<->decode pipelines
* improved testing of Speex non-interleaved encoding
Fri May 21 14:32:41 EST 2004 Conrad Parker <conrad@metadecks.org>
* Version 0.6.2
Improved handling of first and last blocks of data (bos and eos
packets in Ogg):
* new fish_sound_prepare_truncation() API call
* improved encdec-audio test to keep track of frames in and out,
and warn if unequal. (Currently not set to FAIL on this condition
as it appears to be common for Speex)
Updates to Win32 nmake build files
Wed May 5 21:44:26 EST 2004 Conrad Parker <conrad@metadecks.org>
* Version 0.6.1
Added support for comment packets, tests, and various bugfixes.
* Added fish_sound_comment_() API, <fishsound/comments.h>
* Fixed segv bug in decoding stereo Speex to non-interleaved
* Added test for encode/decode pipeline with a variety of
combinations of format, interleave, samplerate, channels and
buffer size.
* Added tests for comments data structure and encode/decode pipeline
* Added fish_sound_{get,set}_frameno() API calls
Wed Mar 24 17:53:55 EST 2004 Conrad Parker <conrad@metadecks.org>
* Version 0.6.0
* moved encode and decode to examples, added documentation for each
* added fish_sound_{get,set}_interleave() api calls
* various bugfixes from zen and silvia
* updated win32 dev files from silvia
Sun Mar 07 17:30:00 EST 2004 Silvia Pfeiffer <Silvia.Pfeiffer@csiro.au>
* Version 0.5.41
* fixed up windows port and release preparation with
REAME files etc.
Some time in the year 2003...
* A new fish was born...
* ... by Conrad Parker <Conrad.Parker@csiro.au>
* ... and it had a long unlogged journey...
* before arriving at 0.5.40 . :)

View File

@ -0,0 +1,51 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Mozilla code.
#
# The Initial Developer of the Original Code is the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2007
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Double <chris.double@double.co.nz>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = fishsound
DIRS = \
include \
src \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,36 @@
FishSound, the sound of fish!
-----------------------------
Full documentation is available in doc/fishsound/html/index.html,
or online at http://www.annodex.net/software/libfishsound/html/
Updates are available online at the FishSound homepage:
http://www.annodex.net/software/libfishsound/
libfishsound provides a simple programming interface for decoding and
encoding audio data using Xiph.Org codecs (FLAC, Speex and Vorbis).
libfishsound by itself is designed to handle raw codec streams from a
lower level layer such as UDP datagrams. When these codecs are used in
files, they are commonly encapsulated in Ogg to produce Ogg FLAC, Speex
and Ogg Vorbis files.
This source tarball
-------------------
FishSound has been developed and tested on GNU/Linux, Darwin/MacOSX
and MS Windows. Installation uses the standard configure, make, make
install sequence; Full details are in the file INSTALL. Read the file
README.win32 for installing under MS Windows.
src/libfishsound/ the library source code.
src/examples/ example tools for programming with libfishsound.
include/ the libfishound include files that will be installed
into the system include directory.
doc/ documentation for libfishsound. The subdirectory
doc/libfishsound is autocreated by doxygen from
comments contained in <fishsound/fishsound.h>
win32/ files necessary to compile under MS Windows.

View File

@ -0,0 +1,7 @@
The source from this directory was copied from the libfishsound-0.9.1
source distribution using the update.sh script. The only changes made
were those applied by update.sh and the addition/upate of Makefile.in
files for the Mozilla build system.
Some files are renamed during the copy to prevent clashes with object
file names with other Mozilla libraries.

View File

@ -0,0 +1,47 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Mozilla code.
#
# The Initial Developer of the Original Code is the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2007
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Double <chris.double@double.co.nz>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = fishsound
DIRS = fishsound
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,55 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Mozilla code.
#
# The Initial Developer of the Original Code is the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2007
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Double <chris.double@double.co.nz>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = fishsound
EXPORTS = \
comments.h \
constants.h \
decode.h \
deprecated.h \
encode.h \
fishsound.h \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,211 @@
/*
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Organisation (CSIRO) Australia
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 name of CSIRO Australia nor the names of its
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 ORGANISATION 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.
*/
#ifndef __FISH_SOUND_COMMENT_H__
#define __FISH_SOUND_COMMENT_H__
/** \file
* Encoding and decoding of comments.
*
* Vorbis and Speex bitstreams
* use a comment format called "Vorbiscomment", defined
* <a href="http://www.xiph.org/ogg/vorbis/doc/v-comment.html">here</a>.
* Many standard comment names (such as TITLE, COPYRIGHT and GENRE) are
* defined in that document.
*
* The following general features of Vorbiscomment are relevant to this API:
* - Each stream has one comment packet, which occurs before any encoded
* audio data in the stream.
* - When encoding, FishSound will generate the comment block and pass it
* to the encoded() callback in sequence, just like any other packet.
* Hence, all comments must be set before any call to fish_sound_encode_*().
* - When decoding, FishSound will decode the comment block before calling
* the first decoded() callback. Hence, retrieving comment data is possible
* from as soon as the decoded() callback is first called.
*
* Each comment block contains one Vendor string, which can be retrieved
* with fish_sound_comment_get_vendor(). When encoding, this string is
* effectively fixed by the codec libraries; it cannot be set by the
* application.
*
* The rest of a comment block consists of \a name = \a value pairs, with
* the following restrictions:
* - Both the \a name and \a value must be non-empty
* - The \a name is case-insensitive and must consist of ASCII within the
* range 0x20 to 0x7D inclusive, 0x3D ('=') excluded.
* - The \a name is not unique; multiple entries may exist with equivalent
* \a name within a Vorbiscomment block.
* - The \a value may be any UTF-8 string.
*
* \section comments_get Retrieving comments
*
* FishSound contains API methods to iterate through all comments associated
* with a FishSound* handle (fish_sound_comment_first() and
* fish_sound_comment_next(), and to iterate through comments matching a
* particular name (fish_sound_comment_first_byname() and
* fish_sound_comment_next_byname()). Given that multiple comments may exist
* with the same \a name, you should not use
* fish_sound_comment_first_byname() as a simple "get" function.
*
* \section comments_set Encoding comments
*
* For encoding, FishSound contains API methods for adding comments
* (fish_sound_comment_add() and fish_sound_comment_add_byname()
* and for removing comments
* (fish_sound_comment_remove() and fish_sound_comment_remove_byname()).
*/
#include <fishsound/fishsound.h>
/**
* A comment.
*/
typedef struct {
/** The name of the comment, eg. "AUTHOR" */
char * name;
/** The value of the comment, as UTF-8 */
char * value;
} FishSoundComment;
#ifdef __cplusplus
extern "C" {
#endif
/**
* Retrieve the vendor string.
* \param fsound A FishSound* handle
* \returns A read-only copy of the vendor string
* \retval NULL No vendor string is associated with \a fsound,
* or \a fsound is NULL.
*/
const char *
fish_sound_comment_get_vendor (FishSound * fsound);
/**
* Retrieve the first comment.
* \param fsound A FishSound* handle
* \returns A read-only copy of the first comment, or NULL if no comments
* exist for this FishSound* object.
*/
const FishSoundComment *
fish_sound_comment_first (FishSound * fsound);
/**
* Retrieve the next comment.
* \param fsound A FishSound* handle
* \param comment The previous comment.
* \returns A read-only copy of the comment immediately following the given
* comment.
*/
const FishSoundComment *
fish_sound_comment_next (FishSound * fsound, const FishSoundComment * comment);
/**
* Retrieve the first comment with a given name.
* \param fsound A FishSound* handle
* \param name the name of the comment to retrieve.
* \returns A read-only copy of the first comment matching the given \a name.
* \retval NULL no match was found.
* \note If \a name is NULL, the behaviour is the same as for
* fish_sound_comment_first()
*/
const FishSoundComment *
fish_sound_comment_first_byname (FishSound * fsound, char * name);
/**
* Retrieve the next comment following and with the same name as a given
* comment.
* \param fsound A FishSound* handle
* \param comment A comment
* \returns A read-only copy of the next comment with the same name as
* \a comment.
* \retval NULL no further comments with the same name exist for
* this FishSound* object.
*/
const FishSoundComment *
fish_sound_comment_next_byname (FishSound * fsound,
const FishSoundComment * comment);
/**
* Add a comment
* \param fsound A FishSound* handle (created with mode FISH_SOUND_ENCODE)
* \param comment The comment to add
* \retval 0 Success
* \retval FISH_SOUND_ERR_BAD \a fsound is not a valid FishSound* handle
* \retval FISH_SOUND_ERR_INVALID Operation not suitable for this FishSound
*/
int
fish_sound_comment_add (FishSound * fsound, FishSoundComment * comment);
/**
* Add a comment by name and value.
* \param fsound A FishSound* handle (created with mode FISH_SOUND_ENCODE)
* \param name The name of the comment to add
* \param value The contents of the comment to add
* \retval 0 Success
* \retval FISH_SOUND_ERR_BAD \a fsound is not a valid FishSound* handle
* \retval FISH_SOUND_ERR_INVALID Operation not suitable for this FishSound
*/
int
fish_sound_comment_add_byname (FishSound * fsound, const char * name,
const char * value);
/**
* Remove a comment
* \param fsound A FishSound* handle (created with FISH_SOUND_ENCODE)
* \param comment The comment to remove.
* \retval 1 Success: comment removed
* \retval 0 No-op: comment not found, nothing to remove
* \retval FISH_SOUND_ERR_BAD \a fsound is not a valid FishSound* handle
* \retval FISH_SOUND_ERR_INVALID Operation not suitable for this FishSound
*/
int
fish_sound_comment_remove (FishSound * fsound, FishSoundComment * comment);
/**
* Remove all comments with a given name.
* \param fsound A FishSound* handle (created with FISH_SOUND_ENCODE)
* \param name The name of the comments to remove
* \retval ">= 0" The number of comments removed
* \retval FISH_SOUND_ERR_BAD \a fsound is not a valid FishSound* handle
* \retval FISH_SOUND_ERR_INVALID Operation not suitable for this FishSound
*/
int
fish_sound_comment_remove_byname (FishSound * fsound, char * name);
#ifdef __cplusplus
}
#endif
#endif /* __FISH_SOUND_COMMENTS_H__ */

View File

@ -0,0 +1,106 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Do not build decoding support */
#define FS_DECODE 1
/* Do not build encoding support */
#define FS_ENCODE 0
/* Define to build experimental code */
/* #undef FS_EXPERIMENTAL */
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have libFLAC */
#define HAVE_FLAC 0
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define if have libsndfile */
/* #undef HAVE_LIBSNDFILE1 */
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define if have liboggz */
/* #undef HAVE_OGGZ */
/* Define to 1 if you have libspeex */
#define HAVE_SPEEX 0
/* Define to 1 if you have libspeex 1.1.x */
/* #undef HAVE_SPEEX_1_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/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have libvorbis */
#define HAVE_VORBIS 1
/* Define to 1 if you have libvorbisenc */
#define HAVE_VORBISENC 0
/* Name of package */
#define PACKAGE "libfishsound"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
#define PACKAGE_NAME ""
/* Define to the full name and version of this package. */
#define PACKAGE_STRING ""
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME ""
/* Define to the version of this package. */
#define PACKAGE_VERSION ""
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Version number of package */
#define VERSION "0.9.1"
/* Define to 1 if your processor stores words with the most significant byte
first (like Motorola and SPARC, unlike Intel and VAX). */
/* #undef WORDS_BIGENDIAN */
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
#undef FS_ENCODE
#define FS_ENCODE 0
#undef HAVE_FLAC
#define HAVE_FLAC 0
#undef HAVE_OGGZ
#define HAVE_OGGZ 1
#undef HAVE_SPEEX
#define HAVE_SPEEX 0
#undef HAVE_VORBIS
#define HAVE_VORBIS 1
#undef HAVE_VORBISENC
#define HAVE_VORBISENC 0
#undef DEBUG

View File

@ -0,0 +1,119 @@
/*
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Organisation (CSIRO) Australia
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 name of CSIRO Australia nor the names of its
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 ORGANISATION 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.
*/
#ifndef __FISH_SOUND_CONSTANTS_H__
#define __FISH_SOUND_CONSTANTS_H__
/** \file
* Constants used by libfishsound
*/
/** Mode of operation (encode or decode) */
typedef enum _FishSoundMode {
/** Decode */
FISH_SOUND_DECODE = 0x10,
/** Encode */
FISH_SOUND_ENCODE = 0x20
} FishSoundMode;
/** Identifiers for supported codecs */
typedef enum _FishSoundCodecID {
/** Unknown */
FISH_SOUND_UNKNOWN = 0x00,
/** Vorbis */
FISH_SOUND_VORBIS = 0x01,
/** Speex */
FISH_SOUND_SPEEX = 0x02,
/** Flac */
FISH_SOUND_FLAC = 0x03
} FishSoundCodecID;
/** Decode callback return values */
typedef enum _FishSoundStopCtl {
/** Continue calling decode callbacks */
FISH_SOUND_CONTINUE = 0,
/** Stop calling callbacks, but retain buffered data */
FISH_SOUND_STOP_OK = 1,
/** Stop calling callbacks, and purge buffered data */
FISH_SOUND_STOP_ERR = -1
} FishSoundStopCtl;
/** Command codes */
typedef enum _FishSoundCommand {
/** No operation */
FISH_SOUND_COMMAND_NOP = 0x0000,
/** Retrieve the FishSoundInfo */
FISH_SOUND_GET_INFO = 0x1000,
/** Query if multichannel audio should be interpreted as interleaved */
FISH_SOUND_GET_INTERLEAVE = 0x2000,
/** Set to 1 to interleave, 0 to non-interleave */
FISH_SOUND_SET_INTERLEAVE = 0x2001,
FISH_SOUND_SET_ENCODE_VBR = 0x4000,
FISH_SOUND_COMMAND_MAX
} FishSoundCommand;
/** Error values */
typedef enum _FishSoundError {
/** No error */
FISH_SOUND_OK = 0,
/** generic error */
FISH_SOUND_ERR_GENERIC = -1,
/** Not a valid FishSound* handle */
FISH_SOUND_ERR_BAD = -2,
/** The requested operation is not suitable for this FishSound* handle */
FISH_SOUND_ERR_INVALID = -3,
/** Functionality disabled at build time */
FISH_SOUND_ERR_DISABLED = -10,
/** Too few bytes passed to fish_sound_identify() */
FISH_SOUND_ERR_SHORT_IDENTIFY = -20,
/** Comment violates VorbisComment restrictions */
FISH_SOUND_ERR_COMMENT_INVALID = -21
} FishSoundError;
#endif /* __FISH_SOUND_CONSTANTS_H__ */

View File

@ -0,0 +1,123 @@
/*
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Organisation (CSIRO) Australia
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 name of CSIRO Australia nor the names of its
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 ORGANISATION 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.
*/
#ifndef __FISH_SOUND_DECODE_H__
#define __FISH_SOUND_DECODE_H__
#ifdef __cplusplus
extern "C" {
#endif
/** \file
* Decode functions and callback prototypes
*/
/**
* Signature of a callback for libfishsound to call when it has decoded
* PCM audio data, and you want this provided as non-interleaved floats.
* \param fsound The FishSound* handle
* \param pcm The decoded audio
* \param frames The count of frames decoded
* \param user_data Arbitrary user data
* \retval FISH_SOUND_CONTINUE Continue decoding
* \retval FISH_SOUND_STOP_OK Stop decoding immediately and
* return control to the fish_sound_decode() caller
* \retval FISH_SOUND_STOP_ERR Stop decoding immediately, purge buffered
* data, and return control to the fish_sound_decode() caller
*/
typedef int (*FishSoundDecoded_Float) (FishSound * fsound, float * pcm[],
long frames, void * user_data);
/**
* Signature of a callback for libfishsound to call when it has decoded
* PCM audio data, and you want this provided as interleaved floats.
* \param fsound The FishSound* handle
* \param pcm The decoded audio
* \param frames The count of frames decoded
* \param user_data Arbitrary user data
* \retval FISH_SOUND_CONTINUE Continue decoding
* \retval FISH_SOUND_STOP_OK Stop decoding immediately and
* return control to the fish_sound_decode() caller
* \retval FISH_SOUND_STOP_ERR Stop decoding immediately, purge buffered
* data, and return control to the fish_sound_decode() caller
*/
typedef int (*FishSoundDecoded_FloatIlv) (FishSound * fsound, float ** pcm,
long frames, void * user_data);
/**
* Set the callback for libfishsound to call when it has a block of decoded
* PCM audio ready, and you want this provided as non-interleaved floats.
* \param fsound A FishSound* handle (created with mode FISH_SOUND_DECODE)
* \param decoded The callback to call
* \param user_data Arbitrary user data to pass to the callback
* \returns 0 on success, -1 on failure
*/
int fish_sound_set_decoded_float (FishSound * fsound,
FishSoundDecoded_Float decoded,
void * user_data);
/**
* Set the callback for libfishsound to call when it has a block of decoded
* PCM audio ready, and you want this provided as interleaved floats.
* \param fsound A FishSound* handle (created with mode FISH_SOUND_DECODE)
* \param decoded The callback to call
* \param user_data Arbitrary user data to pass to the callback
* \returns 0 on success, -1 on failure
*/
int fish_sound_set_decoded_float_ilv (FishSound * fsound,
FishSoundDecoded_FloatIlv decoded,
void * user_data);
/**
* Decode a block of compressed data.
* No internal buffering is done, so a complete compressed audio packet
* must be passed each time.
* \param fsound A FishSound* handle (created with mode FISH_SOUND_DECODE)
* \param buf A buffer containing a compressed audio packet
* \param bytes A count of bytes to decode (i.e. the length of buf)
* \returns The number of bytes consumed
* \retval FISH_SOUND_ERR_STOP_OK Decoding was stopped by a FishSoundDecode*
* callback returning FISH_SOUND_STOP_OK before any input bytes were consumed.
* This will occur when PCM is decoded from previously buffered input, and
* stopping is immediately requested.
* \retval FISH_SOUND_ERR_STOP_ERR Decoding was stopped by a FishSoundDecode*
* callback returning FISH_SOUND_STOP_ERR before any input bytes were consumed.
* This will occur when PCM is decoded from previously buffered input, and
* stopping is immediately requested.
*/
long fish_sound_decode (FishSound * fsound, unsigned char * buf, long bytes);
#ifdef __cplusplus
}
#endif
#endif /* __FISH_SOUND_DECODE_H__ */

View File

@ -0,0 +1,128 @@
/*
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Organisation (CSIRO) Australia
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 name of CSIRO Australia nor the names of its
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 ORGANISATION 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.
*/
#ifndef __FISH_SOUND_DEPRECATED_H__
#define __FISH_SOUND_DEPRECATED_H__
/** \file
* Deprecated interfaces
*/
#ifdef __cplusplus
extern "C" {
#endif
/**
* DEPRECATED FUNCTION.
* Set the PCM format used by a FishSound object. The default value is
* non-interleaved.
* Prior to libfishsound 0.7.0, you would (optionally) specify whether you
* wanted to receive interleaved or per-channel PCM data using
* fish_sound_set_interleave(), the default being per-channel
* (non-interleaved) PCM.
* Whether or not your decoded callback expects interleaved or
* non-interleaved data is now implied by the particular
* fish_sound_set_decoded_TYPE() method you use to set it, such as
* fish_sound_set_decoded_float() or fish_sound_set_decode_float_ilv().
*
* \param fsound A FishSound* handle
* \param interleave Whether to use interleaved PCM or not. Valid values are
* 0 for non-interleaved, and 1 for interleaved.
* \retval 0 Success
* \retval -1 Invalid \a fsound
*/
int fish_sound_set_interleave (FishSound * fsound, int interleave);
/**
* DEPRECATED TYPE.
* Signature of a callback for libfishsound to call when it has decoded
* PCM audio data, and you want this provided as floats using the current
* interleave method as set by fish_sound_set_interleave().
*/
typedef FishSoundDecoded_Float FishSoundDecoded;
/**
* DEPRECATED FUNCTION.
* Set the callback for libfishsound to call when it has a block of decoded
* PCM audio ready, and you want this provided as floats using the current
* interleave method as set by fish_sound_set_interleave().
* This function, and fish_sound_set_interleave(), have been superceded by
* the typesafe fish_sound_set_decoded_TYPE() callbacks, such as
* fish_sound_set_decoded_float() or fish_sound_set_decoded_float_ilv().
*
* \param fsound A FishSound* handle (created with mode FISH_SOUND_DECODE)
* \param decoded The callback to call
* \param user_data Arbitrary user data to pass to the callback
* \returns 0 on success, -1 on failure
*/
int fish_sound_set_decoded_callback (FishSound * fsound,
FishSoundDecoded decoded,
void * user_data);
/**
* DEPRECATED FUNCTION.
* Set the PCM format used by a FishSound object. The default value is
* non-interleaved.
* Prior to libfishsound 0.7.0, you would (optionally) specify whether you
* wanted to receive interleaved or per-channel PCM data using
* fish_sound_set_interleave(), the default being per-channel
* (non-interleaved) PCM.
* Whether or not your decoded callback expects interleaved or
* non-interleaved data is now implied by the particular
* fish_sound_set_decoded_TYPE() method you use to set it, such as
* fish_sound_set_decoded_float() or fish_sound_set_decode_float_ilv().
*
* \param fsound A FishSound* handle
* \param interleave Whether to use interleaved PCM or not. Valid values are
* 0 for non-interleaved, and 1 for interleaved.
* \retval 0 Success
* \retval -1 Invalid \a fsound
*/
int fish_sound_set_interleave (FishSound * fsound, int interleave);
/**
* DEPRECATED FUNCTION.
* Encode a block of audio
* \param fsound A FishSound* handle (created with mode FISH_SOUND_ENCODE)
* \param pcm The audio data to encode
* \param frames A count of frames to encode
* \returns The number of frames encoded
* \note For multichannel audio, the audio data is interpreted according
* to the current PCM style
*/
long fish_sound_encode (FishSound * fsound, float ** pcm, long frames);
#ifdef __cplusplus
}
#endif
#endif /* __FISH_SOUND_DEPRECATED_H__ */

View File

@ -0,0 +1,97 @@
/*
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Organisation (CSIRO) Australia
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 name of CSIRO Australia nor the names of its
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 ORGANISATION 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.
*/
#ifndef __FISH_SOUND_ENCODE_H__
#define __FISH_SOUND_ENCODE_H__
#ifdef __cplusplus
extern "C" {
#endif
/** \file
* Encode functions and callback prototypes
*/
/**
* Signature of a callback for libfishsound to call when it has encoded
* data.
* \param fsound The FishSound* handle
* \param buf The encoded data
* \param bytes The count of bytes encoded
* \param user_data Arbitrary user data
* \retval 0 to continue
* \retval non-zero to stop encoding immediately and
* return control to the fish_sound_encode() caller
*/
typedef int (*FishSoundEncoded) (FishSound * fsound, unsigned char * buf,
long bytes, void * user_data);
/**
* Set the callback for libfishsound to call when it has a block of
* encoded data ready
* \param fsound A FishSound* handle (created with mode FISH_SOUND_ENCODE)
* \param encoded The callback to call
* \param user_data Arbitrary user data to pass to the callback
* \returns 0 on success, -1 on failure
*/
int fish_sound_set_encoded_callback (FishSound * fsound,
FishSoundEncoded encoded,
void * user_data);
/**
* Encode a block of PCM audio given as non-interleaved floats.
* \param fsound A FishSound* handle (created with mode FISH_SOUND_ENCODE)
* \param pcm The audio data to encode
* \param frames A count of frames to encode
* \returns The number of frames encoded
* \note For multichannel audio, the audio data is interpreted according
* to the current PCM style
*/
long fish_sound_encode_float (FishSound * fsound, float * pcm[], long frames);
/**
* Encode a block of audio given as interleaved floats.
* \param fsound A FishSound* handle (created with mode FISH_SOUND_ENCODE)
* \param pcm The audio data to encode
* \param frames A count of frames to encode
* \returns The number of frames encoded
* \note For multichannel audio, the audio data is interpreted according
* to the current PCM style
*/
long fish_sound_encode_float_ilv (FishSound * fsound, float ** pcm,
long frames);
#ifdef __cplusplus
}
#endif
#endif /* __FISH_SOUND_ENCODE_H__ */

View File

@ -0,0 +1,589 @@
/*
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Organisation (CSIRO) Australia
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 name of CSIRO Australia nor the names of its
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 ORGANISATION 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.
*/
#ifndef __FISH_SOUND_H__
#define __FISH_SOUND_H__
#include <fishsound/constants.h>
/** \mainpage
*
* \section intro FishSound, the sound of fish!
*
* This is the documentation for the FishSound C API. FishSound provides
* a simple programming interface for decoding and encoding audio data
* using Xiph.Org codecs (FLAC, Speex and Vorbis).
*
* libfishsound by itself is designed to handle raw codec streams from
* a lower level layer such as UDP datagrams.
* When these codecs are used in files, they are commonly encapsulated in
* <a href="http://www.xiph.org/ogg/">Ogg</a> to produce
* <em>Ogg FLAC</em>, <em>Speex</em> and <em>Ogg Vorbis</em> files.
* Example C programs using
* <a href="http://www.annodex.net/software/liboggz/">liboggz</a> to
* read and write these files are provided in the libfishsound sources.
*
* For more information on the design and history of libfishsound, see the
* \link about About \endlink section of this documentation, and the
* <a href="http://www.annodex.net/software/libfishsound/">libfishsound</a>
* homepage.
*
* \subsection contents Contents
*
* - \link fishsound.h fishsound.h \endlink:
* Documentation of the FishSound API.
*
* - \link comments.h Handling comments \endlink:
* How to add and retrieve \a name = \a value metadata in Vorbis and Speex
* streams.
*
* - \link decode Decoding audio data \endlink:
* How to decode audio data with FishSound, including source for a fully
* working Ogg FLAC, Speex and Ogg Vorbis decoder.
*
* - \link encode Encoding audio data \endlink:
* How to encode audio data with FishSound, including source for a fully
* working Ogg FLAC, Speex and Ogg Vorbis encoder.
*
* - \link configuration Configuration \endlink:
* Customizing libfishsound to only decode or encode,
* or to disable support for a particular codec.
*
* - \link building Building \endlink:
* Information related to building software that uses libfishsound.
*
* - \link about About \endlink:
* Design, motivation, history and acknowledgements.
*
* \section Licensing
*
* libfishsound is provided under the following BSD-style open source license:
*
* \include COPYING
*
*/
/** \defgroup about About
*
* \section design Design
* libfishsound provides a simple programming interface for decoding and
* encoding audio data using codecs from
* <a href="http://www.xiph.org/">Xiph.Org</a>.
*
* libfishsound by itself is designed to handle raw codec streams from
* a lower level layer such as UDP datagrams.
* When these codecs are used in files, they are commonly encapsulated in
* <a href="http://www.xiph.org/ogg/">Ogg</a> to produce
* <em>Ogg FLAC</em>, <em>Speex</em> and <em>Ogg Vorbis</em> files.
* Example C programs using
* <a href="http://www.annodex.net/software/liboggz/">liboggz</a> to
* read and write these files are provided in the libfishsound sources.
*
* libfishsound is implemented as a wrapper around the existing codec
* libraries and provides a consistent, higher-level programming
* interface. The motivation for this is twofold: to simplify the task
* of developing application software that supports these codecs,
* and to ensure that valid codec streams are generated.
*
* \section history History
* libfishsound was designed and developed by Conrad Parker on the
* weekend of October 18-19 2003. Previously the author had implemented
* Vorbis and Speex support in the following software:
* - <a href="http://www.metadecks.org/software/sweep/">Sweep</a>, a
* digital audio editor with decoding and GUI control of all encoding
* options of Vorbis and Speex
* - Speex support in the <a href="http://www.xinehq.org/">xine</a>
* multimedia player
* - Vorbis and Speex importers for
* <a href="http://www.annodex.net/software/libannodex/">libannodex</a>,
the basic library for reading and writing
* <a href="http://www.annodex.net/">Annodex.net</a> media files.
*
* The implementation of libfishsound draws heavily on these sources, and
* in turn the original example sources of libvorbis and libvorbisenc by
* Monty, and libspeex by Jean-Marc Valin.
*
* The naming of libfishsound reflects both the Xiph.Org logo and
* the author's reputation as a dirty, smelly old fish.
*
* \section limitations Limitations
*
* libfishsound has been designed to accomodate the various decoding and
* encoding styles required by a wide variety of software. However, as it
* is an abstraction of the underlying libvorbis, libvorbisenc and libspeex
* libraries, it may not be possible to implement some low-level techniques
* that these libraries enable, such as parallelization of Vorbis sub-block
* decoding. Nevertheless it is expected that libfishsound is a useful
* API for most software requiring Vorbis or Speex support, including most
* applications the author has encountered.
*
* \section acknowledgements Acknowledgements
* Much of the API design follows the style of
* <a href="http://www.zip.com.au/~erikd/libsndfile/">libsndfile</a>.
* The author would like to thank Erik de Castro Lopo for feedback on the
* design of libfishsound.
*/
/** \defgroup configuration Configuration
*
* \section platforms Platform-specific configuration
*
* FishSound can be configured on most platforms using the GNU autoconf
* ./configure system described below.
*
* For Win32, see the \link win32 README.win32 \endlink section. You will
* need to edit <tt>win32/config.h</tt> by hand to achieve the customizations
* described below.
*
* \section ./configure ./configure
*
* It is possible to customize the functionality of libfishsound
* by using various ./configure flags when
* building it from source; for example you can build a smaller
* version of libfishsound to only decode or encode, or and you can
* choose to disable support for a particular codec.
* By default, both decoding and encoding support is built for all
* codecs found on the system.
*
* For general information about using ./configure, see the file
* \link install INSTALL \endlink
*
* \subsection no_encode Removing encoding support
*
* Configuring with \a --disable-encode will remove all support for encoding:
* - All internal encoding related functions will not be built
* - Any attempt to call fish_sound_new() with \a mode == FISH_SOUND_ENCODE
* will fail, returning NULL
* - Any attempt to call fish_sound_encode_*() will return
* FISH_SOUND_ERR_DISABLED
* - The resulting library will not be linked against libvorbisenc
*
* \subsection no_decode Removing decoding support
*
* Configuring with \a --disable-decode will remove all support for decoding:
* - All internal decoding related functions will not be built
* - Any attempt to call fish_sound_new() with \a mode == FISH_SOUND_DECODE
* will fail, returning NULL
* - Any attempt to call fish_sound_decode() will return
* FISH_SOUND_ERR_DISABLED
*
* \subsection no_flac Removing FLAC support
*
* Configuring with \a --disable-flac will remove all support for FLAC:
* - All internal FLAC related functions will not be built
* - Any attempt to call fish_sound_new() with \a mode == FISH_SOUND_ENCODE
* and \a fsinfo->format == FISH_SOUND_FLAC will fail, returning NULL
* - The resulting library will not be linked against libFLAC
*
* \subsection no_speex Removing Speex support
*
* Configuring with \a --disable-speex will remove all support for Speex:
* - All internal Speex related functions will not be built
* - Any attempt to call fish_sound_new() with \a mode == FISH_SOUND_ENCODE
* and \a fsinfo->format == FISH_SOUND_SPEEX will fail, returning NULL
* - The resulting library will not be linked against libspeex
*
* \subsection no_vorbis Removing Vorbis support
*
* Configuring with \a --disable-vorbis will remove all support for Vorbis:
* - All internal Vorbis related functions will not be built
* - Any attempt to call fish_sound_new() with \a mode == FISH_SOUND_ENCODE
* and \a fsinfo->format == FISH_SOUND_VORBIS will fail, returning NULL
* - The resulting library will not be linked against libvorbis or libvorbisenc
*
* \subsection summary Configuration summary
*
* Upon successful configuration, you should see something like this:
<pre>
------------------------------------------------------------------------
libfishsound 0.9.0: Automatic configuration OK.
General configuration:
Experimental code: ........... no
Decoding support: ............ yes
Encoding support: ............ yes
Library configuration (./src/libfishsound):
FLAC support: ................ yes
Speex support: ............... yes (1.1.x)
Vorbis support: .............. yes
Example programs (./src/examples):
fishsound-identify fishsound-decode fishsound-encode
Installation paths:
libfishsound: ................ /usr/local/lib
C header files: .............. /usr/local/include/fishsound
Documentation: ............... /usr/local/share/doc/libfishsound
Building:
Type 'make' to compile libfishsound.
Type 'make install' to install libfishsound.
Type 'make check' to run test suite (Valgrind testing not enabled)
Example programs will be built but not installed.
------------------------------------------------------------------------
</pre>
*/
/** \defgroup install Installation
* \section install INSTALL
*
* \include INSTALL
*/
/** \defgroup win32 Building on Win32
* \section win32 README.Win32
*
* \include README.win32
*/
/** \defgroup building Building against libfishsound
*
*
* \section autoconf Using GNU autoconf
*
* If you are using GNU autoconf, you do not need to call pkg-config
* directly. Use the following macro to determine if libfishsound is
* available:
*
<pre>
PKG_CHECK_MODULES(FISHSOUND, fishsound >= 0.6.0,
HAVE_FISHSOUND="yes", HAVE_FISHSOUND="no")
if test "x$HAVE_FISHSOUND" = "xyes" ; then
AC_SUBST(FISHSOUND_CFLAGS)
AC_SUBST(FISHSOUND_LIBS)
fi
</pre>
* (Note that if your application requires FLAC support, you should check
* for a version of fishsound >= 0.9.0).
*
* If libfishsound is found, HAVE_FISHSOUND will be set to "yes", and
* the autoconf variables FISHSOUND_CFLAGS and FISHSOUND_LIBS will
* be set appropriately.
*
* \section pkg-config Determining compiler options with pkg-config
*
* If you are not using GNU autoconf in your project, you can use the
* pkg-config tool directly to determine the correct compiler options.
*
<pre>
FISHSOUND_CFLAGS=`pkg-config --cflags fishsound`
FISHSOUND_LIBS=`pkg-config --libs fishsound`
</pre>
*
*/
/** \file
* The libfishsound C API.
*
* \section general General usage
*
* All access is managed via a FishSound* handle. This is instantiated
* using fish_sound_new() and should be deleted with fish_sound_delete()
* when no longer required. If there is a discontinuity in the input
* data (eg. after seeking in an input file), call fish_sound_reset() to
* reset the internal codec state.
*
* \section decoding Decoding
*
* libfishsound provides callback based decoding: you feed it encoded audio
* data, and it will call your callback with decoded PCM. A more detailed
* explanation and a full example of decoding Ogg FLAC, Speex and Ogg Vorbis
* files is provided in the \link decode Decoding audio data \endlink section.
*
* \section encoding Encoding
*
* libfishsound provides callback based encoding: you feed it PCM audio,
* and it will call your callback with encoded audio data. A more detailed
* explanation and a full example of encoding Ogg FLAC, Speex and Ogg Vorbis
* files is provided in the \link encode Encoding audio data \endlink section.
*/
/** \defgroup decode Decoding audio data
*
* To decode audio data using libfishsound:
*
* - create a FishSound* object with mode FISH_SOUND_DECODE. fish_sound_new()
* will return a new FishSound* object, initialised for decoding, and the
* FishSoundInfo structure will be cleared.
* - provide a FishSoundDecoded_* callback for libfishsound to call when it has
* decoded audio.
* - (optionally) specify whether you want to receive interleaved or
* per-channel PCM data, using a fish_sound_set_interleave().
* The default is for per-channel (non-interleaved) PCM.
* - feed encoded audio data to libfishsound via fish_sound_decode().
* libfishsound will decode the audio for you, calling the FishSoundDecoded_*
* callback you provided earlier each time it has a block of audio ready.
* - when finished, call fish_sound_delete().
*
* This procedure is illustrated in src/examples/fishsound-decode.c.
* Note that this example additionally:
* - uses <a href="http://www.annodex.net/software/liboggz/">liboggz</a> to
* demultiplex audio data from an Ogg encapsulated FLAC, Speex or Vorbis
* stream. The step of feeding encoded data to libfishsound is done within
* the OggzReadPacket callback.
* - uses <a href="http://www.mega-nerd.com/libsndfile/">libsndfile</a> to
* write the decoded audio to a WAV file.
*
* Hence this example code demonstrates all that is needed to decode
* Ogg FLAC, Speex or Ogg Vorbis files:
*
* \include fishsound-decode.c
*/
/** \defgroup encode Encoding audio data
*
* To encode audio data using libfishsound:
*
* - create a FishSound* object with mode FISH_SOUND_ENCODE, and with a
* FishSoundInfo structure filled in with the required encoding parameters.
* fish_sound_new() will return a new FishSound* object initialised for
* encoding.
* - provide a FishSoundEncoded callback for libfishsound to call when it
* has a block of encoded audio
* - feed raw PCM audio data to libfishsound via fish_sound_encode_*().
* libfishsound will encode the audio for you, calling the FishSoundEncoded
* callback you provided earlier each time it has a block of encoded audio
* ready.
* - when finished, call fish_sound_delete().
*
* This procedure is illustrated in src/examples/fishsound-encode.c.
* Note that this example additionally:
* - uses <a href="http://www.mega-nerd.com/libsndfile/">libsndfile</a> to
* read input from a PCM audio file (WAV, AIFF, etc.)
* - uses <a href="http://www.annodex.net/software/liboggz/">liboggz</a> to
* encapsulate the encoded FLAC, Speex or Vorbis data in an Ogg stream.
*
* Hence this example code demonstrates all that is needed to encode
* Ogg FLAC, Speex and Ogg Vorbis files:
*
* \include fishsound-encode.c
*/
/**
* Info about a particular encoder/decoder instance
*/
typedef struct {
/** Sample rate of audio data in Hz */
int samplerate;
/** Count of channels */
int channels;
/** FISH_SOUND_VORBIS, FISH_SOUND_SPEEX, FISH_SOUND_FLAC etc. */
int format;
} FishSoundInfo;
/**
* Info about a particular sound format
*/
typedef struct {
/** FISH_SOUND_VORBIS, FISH_SOUND_SPEEX, FISH_SOUND_FLAC etc. */
int format;
/** Printable name */
const char * name;
/** Commonly used file extension */
const char * extension;
} FishSoundFormat;
/**
* An opaque handle to a FishSound. This is returned by fishsound_new()
* and is passed to all other fish_sound_*() functions.
*/
typedef void * FishSound;
#ifdef __cplusplus
extern "C" {
#endif
/**
* Identify a codec based on the first few bytes of data.
* \param buf A pointer to the first few bytes of the data
* \param bytes The count of bytes available at buf
* \retval FISH_SOUND_xxxxxx FISH_SOUND_VORBIS, FISH_SOUND_SPEEX or
* FISH_SOUND_FLAC if \a buf was identified as the initial bytes of a
* supported codec
* \retval FISH_SOUND_UNKNOWN if the codec could not be identified
* \retval FISH_SOUND_ERR_SHORT_IDENTIFY if \a bytes is less than 8
* \note If \a bytes is exactly 8, then only a weak check is performed,
* which is fast but may return a false positive.
* \note If \a bytes is greater than 8, then a stronger check is performed
* in which an attempt is made to decode \a buf as the initial header of
* each supported codec. This is unlikely to return a false positive but
* is only useful if \a buf is the entire payload of a packet derived from
* a lower layer such as Ogg framing or UDP datagrams.
*/
int
fish_sound_identify (unsigned char * buf, long bytes);
/**
* Instantiate a new FishSound* handle
* \param mode FISH_SOUND_DECODE or FISH_SOUND_ENCODE
* \param fsinfo Encoder configuration, may be NULL for FISH_SOUND_DECODE
* \returns A new FishSound* handle, or NULL on error
*/
FishSound * fish_sound_new (int mode, FishSoundInfo * fsinfo);
/**
* Flush any internally buffered data, forcing encode
* \param fsound A FishSound* handle
* \returns 0 on success, -1 on failure
*/
long fish_sound_flush (FishSound * fsound);
/**
* Reset the codec state of a FishSound object.
*
* When decoding from a seekable file, fish_sound_reset() should be called
* after any seek operations. See also fish_sound_set_frameno().
*
* \param fsound A FishSound* handle
* \returns 0 on success, -1 on failure
*/
int fish_sound_reset (FishSound * fsound);
/**
* Delete a FishSound object
* \param fsound A FishSound* handle
* \returns 0 on success, -1 on failure
*/
int fish_sound_delete (FishSound * fsound);
/**
* Command interface
* \param fsound A FishSound* handle
* \param command The command action
* \param data Command data
* \param datasize Size of the data in bytes
* \returns 0 on success, -1 on failure
*/
int fish_sound_command (FishSound * fsound, int command, void * data,
int datasize);
/**
* Query whether a FishSound object is using interleaved PCM
* \param fsound A FishSound* handle
* \retval 0 \a fsound uses non-interleaved PCM
* \retval 1 \a fsound uses interleaved PCM
* \retval -1 Invalid \a fsound
*/
int fish_sound_get_interleave (FishSound * fsound);
/**
* Query the current frame number of a FishSound object.
*
* For decoding, this is the greatest frame index that has been decoded and
* made available to a FishSoundDecoded callback. This function is safe to
* call from within a FishSoundDecoded callback, and corresponds to the frame
* number of the last frame in the current decoded block.
*
* For encoding, this is the greatest frame index that has been encoded. This
* function is safe to call from within a FishSoundEncoded callback, and
* corresponds to the frame number of the last frame encoded in the current
* block.
*
* \param fsound A FishSound* handle
* \returns The current frame number
* \retval -1 Invalid \a fsound
*/
long fish_sound_get_frameno (FishSound * fsound);
/**
* Set the current frame number of a FishSound object.
*
* When decoding from a seekable file, fish_sound_set_frameno() should be
* called after any seek operations, otherwise the value returned by
* fish_sound_get_frameno() will simply continue to increment. See also
* fish_sound_reset().
*
* \param fsound A FishSound* handle
* \param frameno The current frame number.
* \retval 0 Success
* \retval -1 Invalid \a fsound
*/
int fish_sound_set_frameno (FishSound * fsound, long frameno);
/**
* Prepare truncation details for the next block of data.
* The semantics of these parameters derives directly from Ogg encapsulation
* of Vorbis, described
* <a href="http://www.xiph.org/ogg/vorbis/doc/Vorbis_I_spec.html#vorbis-over-ogg">here</a>.
*
* When decoding from Ogg, you should call this function with the \a granulepos
* and \a eos of the \a ogg_packet structure. This call should be made before
* passing the packet's data to fish_sound_decode(). Failure to do so may
* result in minor decode errors on the first and/or last packet of the stream.
*
* When encoding into Ogg, you should call this function with the \a granulepos
* and \a eos that will be used for the \a ogg_packet structure. This call
* should be made before passing the block of audio data to
* fish_sound_encode_*(). Failure to do so may result in minor encoding errors
* on the first and/or last packet of the stream.
*
* \param fsound A FishSound* handle
* \param next_granulepos The "granulepos" for the next block to decode.
* If unknown, set \a next_granulepos to -1. Otherwise,
* \a next_granulepos specifies the frameno of the final frame in the
* block. This is authoritative, hence can be used to indicate
* various forms of truncation at the beginning or end of a stream.
* Mid-stream, a later-than-expected "granulepos" indicates that some
* data was missing.
* \param next_eos A boolean indicating whether the next data block will be
* the last in the stream.
* \retval 0 Success
* \retval -1 Invalid \a fsound
*/
int fish_sound_prepare_truncation (FishSound * fsound, long next_granulepos,
int next_eos);
#ifdef __cplusplus
}
#endif
#include <fishsound/decode.h>
#include <fishsound/encode.h>
#include <fishsound/comments.h>
#include <fishsound/deprecated.h>
#endif /* __FISH_SOUND_H__ */

View File

@ -0,0 +1,47 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Mozilla code.
#
# The Initial Developer of the Original Code is the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2007
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Double <chris.double@double.co.nz>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = fishsound
DIRS = libfishsound
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,58 @@
# ***** BEGIN LICENSE BLOCK *****
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
#
# The contents of this file are subject to the Mozilla Public License Version
# 1.1 (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS" basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
# for the specific language governing rights and limitations under the
# License.
#
# The Original Code is Mozilla code.
#
# The Initial Developer of the Original Code is the Mozilla Corporation.
# Portions created by the Initial Developer are Copyright (C) 2007
# the Initial Developer. All Rights Reserved.
#
# Contributor(s):
# Chris Double <chris.double@double.co.nz>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
# in which case the provisions of the GPL or the LGPL are applicable instead
# of those above. If you wish to allow use of your version of this file only
# under the terms of either the GPL or the LGPL, and not to allow others to
# use your version of this file under the terms of the MPL, indicate your
# decision by deleting the provisions above and replace them with the notice
# and other provisions required by the GPL or the LGPL. If you do not delete
# the provisions above, a recipient may use your version of this file under
# the terms of any one of the MPL, the GPL or the LGPL.
#
# ***** END LICENSE BLOCK *****
DEPTH = ../../../..
topsrcdir = @top_srcdir@
srcdir = @srcdir@
VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
MODULE = fishsound
LIBRARY_NAME = fishsound
FORCE_STATIC_LIB= 1
CSRCS = \
fishsound_comments.c \
fishsound_decode.c \
fishsound.c \
fs_vector.c \
fishsound_speex.c \
fishsound_vorbis.c \
fishsound_flac.c \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,106 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Do not build decoding support */
#define FS_DECODE 1
/* Do not build encoding support */
#define FS_ENCODE 0
/* Define to build experimental code */
/* #undef FS_EXPERIMENTAL */
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have libFLAC */
#define HAVE_FLAC 0
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define if have libsndfile */
/* #undef HAVE_LIBSNDFILE1 */
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define if have liboggz */
/* #undef HAVE_OGGZ */
/* Define to 1 if you have libspeex */
#define HAVE_SPEEX 0
/* Define to 1 if you have libspeex 1.1.x */
/* #undef HAVE_SPEEX_1_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/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have libvorbis */
#define HAVE_VORBIS 1
/* Define to 1 if you have libvorbisenc */
#define HAVE_VORBISENC 0
/* Name of package */
#define PACKAGE "libfishsound"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
#define PACKAGE_NAME ""
/* Define to the full name and version of this package. */
#define PACKAGE_STRING ""
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME ""
/* Define to the version of this package. */
#define PACKAGE_VERSION ""
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Version number of package */
#define VERSION "0.9.1"
/* Define to 1 if your processor stores words with the most significant byte
first (like Motorola and SPARC, unlike Intel and VAX). */
/* #undef WORDS_BIGENDIAN */
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
#undef FS_ENCODE
#define FS_ENCODE 0
#undef HAVE_FLAC
#define HAVE_FLAC 0
#undef HAVE_OGGZ
#define HAVE_OGGZ 1
#undef HAVE_SPEEX
#define HAVE_SPEEX 0
#undef HAVE_VORBIS
#define HAVE_VORBIS 1
#undef HAVE_VORBISENC
#define HAVE_VORBISENC 0
#undef DEBUG

View File

@ -0,0 +1,68 @@
/*
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Organisation (CSIRO) Australia
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 name of CSIRO Australia nor the names of its
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 ORGANISATION 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.
*/
#ifndef __FISH_SOUND_CONVERT_H__
#define __FISH_SOUND_CONVERT_H__
/* inline functions */
static inline void
_fs_deinterleave (float ** src, float * dest[],
long frames, int channels, float mult_factor)
{
int i, j;
float * d, * s = (float *)src;
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
d = dest[j];
d[i] = s[i*channels + j] * mult_factor;
}
}
}
static inline void
_fs_interleave (float * src[], float ** dest,
long frames, int channels, float mult_factor)
{
int i, j;
float * s, * d = (float *)dest;
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
s = src[j];
d[i*channels + j] = s[i] * mult_factor;
}
}
}
#endif /* __FISH_SOUND_CONVERT_H__ */

View File

@ -0,0 +1,415 @@
/*
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Organisation (CSIRO) Australia
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 name of CSIRO Australia nor the names of its
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 ORGANISATION 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.
*/
#ifndef __FISH_SOUND_CONVERT_C_H__
#define __FISH_SOUND_CONVERT_C_H__
#include <string.h>
#include <ogg/ogg.h>
/* inline functions */
static inline void
_fs_deinterleave_s_s (short ** src, short * dest[],
long frames, int channels)
{
int i, j;
short * d, * s = (short *)src;
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
d = dest[j];
d[i] = s[i*channels + j];
}
}
}
static inline void
_fs_deinterleave_s_i (short ** src, int * dest[], long frames, int channels)
{
int i, j;
short * s = (short *)src;
int * d;
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
d = dest[j];
d[i] = (int) s[i*channels + j];
}
}
}
static inline void
_fs_deinterleave_s_f (short ** src, float * dest[], long frames, int channels,
float mult)
{
int i, j;
short * s = (short *)src;
float * d;
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
d = dest[j];
d[i] = ((float) s[i*channels + j]) * mult;
}
}
}
static inline void
_fs_deinterleave_s_d (short ** src, double * dest[], long frames, int channels,
double mult)
{
int i, j;
short * s = (short *)src;
double * d;
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
d = dest[j];
d[i] = ((double) s[i*channels + j]) * mult;
}
}
}
static inline void
_fs_deinterleave_f_s (float ** src, short * dest[],
long frames, int channels, float mult)
{
int i, j;
float * s = (float *)src;
short * d;
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
d = dest[j];
d[i] = (short) (s[i*channels + j] * mult);
}
}
}
static inline void
_fs_deinterleave_f_i (float ** src, int * dest[],
long frames, int channels, float mult)
{
int i, j;
float * s = (float *)src;
int * d;
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
d = dest[j];
d[i] = (int) (s[i*channels + j] * mult);
}
}
}
static inline void
_fs_deinterleave_f_f (float ** src, float * dest[],
long frames, int channels, float mult)
{
int i, j;
float * s = (float *)src, * d;
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
d = dest[j];
d[i] = s[i*channels + j] * mult;
}
}
}
static inline void
_fs_deinterleave_f_d (float ** src, double * dest[],
long frames, int channels, double mult)
{
int i, j;
float * s = (float *)src;
double * d;
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
d = dest[j];
d[i] = (double) s[i*channels + j] * mult;
}
}
}
static inline void
_fs_interleave_f_s (float * src[], short ** dest,
long frames, int channels, float mult)
{
int i, j;
float * s;
short * d = (short *)dest;
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
s = src[j];
d[i*channels + j] = (short) (s[i] * mult);
}
}
}
static inline void
_fs_interleave_s_s (short * src[], short ** dest,
long frames, int channels)
{
int i, j;
short * s, * d = (short *)dest;
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
s = src[j];
d[i*channels + j] = s[i];
}
}
}
static inline void
_fs_interleave_s_f (short * src[], float ** dest,
long frames, int channels, float mult)
{
int i, j;
short * s;
float * d = (float *)dest;
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
s = src[j];
d[i*channels + j] = (float) (s[i] * mult);
}
}
}
static inline ogg_int32_t CLIP_TO_15(ogg_int32_t x) {
int ret=x;
ret-= ((x<=32767)-1)&(x-32767);
ret-= ((x>=-32768)-1)&(x+32768);
return(ret);
}
static inline void
_fs_interleave_i_s (ogg_int32_t * src[], short ** dest,
long frames, int channels, int shift)
{
int i, j;
ogg_int32_t * s;
short * d = (short *)dest;
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
s = src[j];
d[i*channels + j] = (short) CLIP_TO_15(s[i]>>9);
}
}
}
static inline void
_fs_interleave_i_f (int * src[], float ** dest,
long frames, int channels, float mult)
{
int i, j;
int * s;
float * d = (float *)dest;
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
s = src[j];
d[i*channels + j] = (float) (s[i] * mult);
}
}
}
static inline void
_fs_interleave_f_f (float * src[], float ** dest,
long frames, int channels, float mult)
{
int i, j;
float * s, * d = (float *)dest;
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
s = src[j];
d[i*channels + j] = s[i] * mult;
}
}
}
static inline void
_fs_interleave_d_s (double * src[], short ** dest,
long frames, int channels, double mult)
{
int i, j;
double * s;
short * d = (short *)dest;
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
s = src[j];
d[i*channels + j] = (short) (s[i] * mult);
}
}
}
static inline void
_fs_interleave_d_f (double * src[], float ** dest,
long frames, int channels, float mult)
{
int i, j;
double * s;
float * d = (float *)dest;
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
s = src[j];
d[i*channels + j] = (float) s[i] * mult;
}
}
}
static inline void
_fs_convert_s_s (short * src, short * dest, long samples)
{
memcpy (dest, src, samples * sizeof (short));
}
static inline void
_fs_convert_s_i (short * src, int * dest, long samples)
{
int i;
for (i = 0; i < samples; i++) {
dest[i] = (int) src[i];
}
}
static inline void
_fs_convert_s_f (short * src, float * dest, long samples, float mult)
{
int i;
for (i = 0; i < samples; i++) {
dest[i] = (float) src[i] * mult;
}
}
static inline void
_fs_convert_s_d (short * src, double * dest, long samples, double mult)
{
int i;
for (i = 0; i < samples; i++) {
dest[i] = ((double)src[i]) * mult;
}
}
static inline void
_fs_convert_i_s (int * src, short * dest, long samples)
{
int i;
for (i = 0; i < samples; i++) {
dest[i] = (short) src[i];
}
}
static inline void
_fs_convert_i_f (int * src, float * dest, long samples, float mult)
{
int i;
for (i = 0; i < samples; i++) {
dest[i] = (float) src[i] * mult;
}
}
static inline void
_fs_convert_f_s (float * src, short * dest, long samples, float mult)
{
int i;
for (i = 0; i < samples; i++) {
dest[i] = (short) (src[i] * mult);
}
}
static inline void
_fs_convert_f_i (float * src, int * dest, long samples, float mult)
{
int i;
for (i = 0; i < samples; i++) {
dest[i] = (int) (src[i] * mult);
}
}
static inline void
_fs_convert_f_f (float * src, float * dest, long samples, float mult)
{
int i;
for (i = 0; i < samples; i++) {
dest[i] = src[i] * mult;
}
}
static inline void
_fs_convert_f_d (float * src, double * dest, long samples, double mult)
{
int i;
for (i = 0; i < samples; i++) {
dest[i] = (double)src[i] * mult;
}
}
static inline void
_fs_convert_d_s (double * src, short * dest, long samples, double mult)
{
int i;
for (i = 0; i < samples; i++) {
dest[i] = (short) (src[i] * mult);
}
}
static inline void
_fs_convert_d_f (double * src, float * dest, long samples, float mult)
{
int i;
for (i = 0; i < samples; i++) {
dest[i] = (float)src[i] * mult;
}
}
#endif /* __FISH_SOUND_CONVERT_C_H__ */

View File

@ -0,0 +1,393 @@
/*
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Organisation (CSIRO) Australia
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 name of CSIRO Australia nor the names of its
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 ORGANISATION 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.
*/
/*
* David Schleef, ds@schleef.org
* January, 2005
*/
#ifndef __FISH_SOUND_CONVERT_OIL_H__
#define __FISH_SOUND_CONVERT_OIL_H__
#include <string.h>
#include <ogg/ogg.h>
#include <liboil/liboil.h>
/* inline functions */
static inline void
_fs_deinterleave_s_s (short ** src, short * dest[],
long frames, int channels)
{
int j;
short * s = (short *)src;
#define oil_restride_s16(a,b,c,d,e) oil_conv_u16_s16((uint16_t *)a,b,c,d,e)
for (j = 0; j < channels; j++) {
oil_restride_s16 (dest[j], sizeof(short), s + j,
channels * sizeof(short), frames);
}
}
static inline void
_fs_deinterleave_s_i (short ** src, int * dest[], long frames, int channels)
{
int j;
short * s = (short *)src;
for (j = 0; j < channels; j++) {
oil_conv_s32_s16 (dest[j], sizeof(int), s + j,
channels * sizeof(short), frames);
}
}
static inline void
_fs_deinterleave_s_f (short ** src, float * dest[], long frames, int channels,
float mult)
{
int j;
short * s = (short *)src;
for (j = 0; j < channels; j++) {
oil_conv_f32_s16 (dest[j], sizeof(float), s + j,
channels * sizeof(short), frames);
oil_scalarmult_f32 (dest[j], sizeof (float), dest[j], sizeof(float),
&mult, frames);
}
}
static inline void
_fs_deinterleave_s_d (short ** src, double * dest[], long frames, int channels,
double mult)
{
int j;
short * s = (short *)src;
for (j = 0; j < channels; j++) {
oil_conv_f64_s16 (dest[j], sizeof(double), s + j,
channels * sizeof(short), frames);
oil_scalarmult_f64 (dest[j], sizeof (double), dest[j], sizeof (double),
&mult, frames);
}
}
static inline void
_fs_deinterleave_f_s (float ** src, short * dest[],
long frames, int channels, float mult)
{
int i, j;
float * s = (float *)src;
short * d;
/* FIXME: this needs a temporary buffer for liboil */
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
d = dest[j];
d[i] = (short) (s[i*channels + j] * mult);
}
}
}
static inline void
_fs_deinterleave_f_i (float ** src, int * dest[],
long frames, int channels, float mult)
{
int i, j;
float * s = (float *)src;
int * d;
/* FIXME: this needs a temporary buffer for liboil */
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
d = dest[j];
d[i] = (int) (s[i*channels + j] * mult);
}
}
}
static inline void
_fs_deinterleave_f_f (float ** src, float * dest[],
long frames, int channels, float mult)
{
int j;
float * s = (float *)src;
for (j = 0; j < channels; j++) {
oil_scalarmult_f32 (dest[j], sizeof(float), s + j,
channels * sizeof(float), &mult, frames);
}
}
static inline void
_fs_deinterleave_f_d (float ** src, double * dest[],
long frames, int channels, double mult)
{
int j;
float * s = (float *)src;
for (j = 0; j < channels; j++) {
oil_conv_f64_f32 (dest[j], sizeof(double), s + j,
channels * sizeof(float), frames);
oil_scalarmult_f64 (dest[j], sizeof(double), dest[j],
sizeof(double), &mult, frames);
}
}
static inline void
_fs_interleave_f_s (float * src[], short ** dest,
long frames, int channels, float mult)
{
int i, j;
float * s;
short * d = (short *)dest;
/* FIXME: this needs a temporary buffer for liboil */
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
s = src[j];
d[i*channels + j] = (short) (s[i] * mult);
}
}
}
static inline void
_fs_interleave_s_s (short * src[], short ** dest,
long frames, int channels)
{
int j;
short * d = (short *)dest;
for (j = 0; j < channels; j++) {
oil_restride_s16 (d + j, sizeof (short) * channels, src[j],
sizeof (short), frames);
}
}
static inline void
_fs_interleave_s_f (short * src[], float ** dest,
long frames, int channels, float mult)
{
int j;
float * d = (float *)dest;
for (j = 0; j < channels; j++) {
oil_conv_f32_s16 (d + j, sizeof (float) * channels, src[j],
sizeof (short), frames);
}
oil_scalarmult_f32 (d, sizeof(float), d, sizeof(float), &mult,
channels * frames);
}
static inline ogg_int32_t CLIP_TO_15(ogg_int32_t x) {
int ret=x;
ret-= ((x<=32767)-1)&(x-32767);
ret-= ((x>=-32768)-1)&(x+32768);
return(ret);
}
static inline void
_fs_interleave_i_s (ogg_int32_t * src[], short ** dest,
long frames, int channels, int shift)
{
int i, j;
ogg_int32_t * s;
short * d = (short *)dest;
/* FIXME: shouldn't this use shift? */
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
s = src[j];
d[i*channels + j] = (short) CLIP_TO_15(s[i]>>9);
}
}
}
static inline void
_fs_interleave_i_f (int * src[], float ** dest,
long frames, int channels, float mult)
{
int j;
float * d = (float *)dest;
for (j = 0; j < channels; j++) {
oil_conv_f32_s32 (d + j, sizeof (float) * channels, src[j],
sizeof (int), frames);
}
oil_scalarmult_f32 (d, sizeof(float), d, sizeof(float), &mult,
channels * frames);
}
static inline void
_fs_interleave_f_f (float * src[], float ** dest,
long frames, int channels, float mult)
{
int j;
float * d = (float *)dest;
for (j = 0; j < channels; j++) {
oil_scalarmult_f32 (d + j, sizeof (float) * channels, src[j],
sizeof (float), &mult, frames);
}
}
static inline void
_fs_interleave_d_s (double * src[], short ** dest,
long frames, int channels, double mult)
{
int i, j;
double * s;
short * d = (short *)dest;
/* FIXME: needs temporary buffer */
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
s = src[j];
d[i*channels + j] = (short) (s[i] * mult);
}
}
}
static inline void
_fs_interleave_d_f (double * src[], float ** dest,
long frames, int channels, float mult)
{
int j;
float * d = (float *)dest;
for (j = 0; j < channels; j++) {
oil_conv_f32_f64 (d + j, sizeof (float) * channels, src[j],
sizeof (double), frames);
}
oil_scalarmult_f32 (d, sizeof(float), d, sizeof(float), &mult,
channels * frames);
}
static inline void
_fs_convert_s_s (short * src, short * dest, long samples)
{
memcpy (dest, src, samples * sizeof (short));
}
static inline void
_fs_convert_s_i (short * src, int * dest, long samples)
{
oil_conv_s32_s16 (dest, sizeof(int), src, sizeof(short), samples);
}
static inline void
_fs_convert_s_f (short * src, float * dest, long samples, float mult)
{
oil_conv_f32_s16 (dest, sizeof(float), src, sizeof(short), samples);
oil_scalarmult_f32 (dest, sizeof(float), dest, sizeof(float), &mult, samples);
}
static inline void
_fs_convert_s_d (short * src, double * dest, long samples, double mult)
{
oil_conv_f64_s16 (dest, sizeof(double), src, sizeof(short), samples);
oil_scalarmult_f64 (dest, sizeof(double), dest, sizeof(double), &mult,
samples);
}
static inline void
_fs_convert_i_s (int * src, short * dest, long samples)
{
/* FIXME: should this clip? */
oil_conv_s16_s32 (dest, sizeof(dest), src, sizeof(int), samples);
/* oil_clipconv_s16_s32 (dest, sizeof(dest), src, sizeof(int), samples); */
}
static inline void
_fs_convert_i_f (int * src, float * dest, long samples, float mult)
{
oil_conv_f32_s32 (dest, sizeof(float), src, sizeof(int), samples);
oil_scalarmult_f32 (dest, sizeof(float), dest, sizeof(float), &mult, samples);
}
static inline void
_fs_convert_f_s (float * src, short * dest, long samples, float mult)
{
int i;
/* FIXME: needs temp buffer */
for (i = 0; i < samples; i++) {
dest[i] = (short) (src[i] * mult);
}
}
static inline void
_fs_convert_f_i (float * src, int * dest, long samples, float mult)
{
int i;
/* FIXME: needs temp buffer */
for (i = 0; i < samples; i++) {
dest[i] = (int) (src[i] * mult);
}
}
static inline void
_fs_convert_f_f (float * src, float * dest, long samples, float mult)
{
oil_scalarmult_f32 (dest, sizeof(float), src, sizeof(float), &mult, samples);
}
static inline void
_fs_convert_f_d (float * src, double * dest, long samples, double mult)
{
oil_conv_f64_f32 (dest, sizeof(double), src, sizeof(float), samples);
oil_scalarmult_f64 (dest, sizeof(double), dest, sizeof(double), &mult, samples);
}
static inline void
_fs_convert_d_s (double * src, short * dest, long samples, double mult)
{
int i;
/* FIXME: needs temp buffer */
for (i = 0; i < samples; i++) {
dest[i] = (short) (src[i] * mult);
}
}
static inline void
_fs_convert_d_f (double * src, float * dest, long samples, float mult)
{
int i;
/* FIXME: needs temp buffer */
for (i = 0; i < samples; i++) {
dest[i] = (float)src[i] * mult;
}
}
#endif /* __FISH_SOUND_CONVERT_OIL_H__ */

View File

@ -0,0 +1,253 @@
/*
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Organisation (CSIRO) Australia
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 name of CSIRO Australia nor the names of its
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 ORGANISATION 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.
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include "private.h"
int
fish_sound_identify (unsigned char * buf, long bytes)
{
if (bytes < 8) return FISH_SOUND_ERR_SHORT_IDENTIFY;
if (HAVE_VORBIS &&
fish_sound_vorbis_identify (buf, bytes) != FISH_SOUND_UNKNOWN)
return FISH_SOUND_VORBIS;
if (HAVE_SPEEX &&
fish_sound_speex_identify (buf, bytes) != FISH_SOUND_UNKNOWN)
return FISH_SOUND_SPEEX;
if (fish_sound_flac_identify (buf, bytes) != FISH_SOUND_UNKNOWN)
return FISH_SOUND_FLAC;
return FISH_SOUND_UNKNOWN;
}
int
fish_sound_set_format (FishSound * fsound, int format)
{
if (format == FISH_SOUND_VORBIS) {
fsound->codec = fish_sound_vorbis_codec ();
} else if (format == FISH_SOUND_SPEEX) {
fsound->codec = fish_sound_speex_codec ();
} else if (format == FISH_SOUND_FLAC) {
fsound->codec = fish_sound_flac_codec ();
} else {
return -1;
}
if (fsound->codec && fsound->codec->init)
fsound->codec->init (fsound);
fsound->info.format = format;
return format;
}
FishSound *
fish_sound_new (int mode, FishSoundInfo * fsinfo)
{
FishSound * fsound;
if (!FS_DECODE && mode == FISH_SOUND_DECODE) return NULL;
if (!FS_ENCODE && mode == FISH_SOUND_ENCODE) return NULL;
if (mode == FISH_SOUND_ENCODE) {
if (fsinfo == NULL) {
return NULL;
} else {
if (!(HAVE_VORBIS && HAVE_VORBISENC)) {
if (fsinfo->format == FISH_SOUND_VORBIS) return NULL;
}
if (!HAVE_SPEEX) {
if (fsinfo->format == FISH_SOUND_SPEEX) return NULL;
}
if (!HAVE_FLAC) {
if (fsinfo->format == FISH_SOUND_FLAC) return NULL;
}
}
} else if (mode != FISH_SOUND_DECODE) {
return NULL;
}
fsound = fs_malloc (sizeof (FishSound));
fsound->mode = mode;
fsound->interleave = 0;
fsound->frameno = 0;
fsound->next_granulepos = -1;
fsound->next_eos = 0;
fsound->codec = NULL;
fsound->codec_data = NULL;
fsound->callback.encoded = NULL;
fsound->user_data = NULL;
fish_sound_comments_init (fsound);
if (mode == FISH_SOUND_DECODE) {
fsound->info.samplerate = 0;
fsound->info.channels = 0;
fsound->info.format = FISH_SOUND_UNKNOWN;
} else if (mode == FISH_SOUND_ENCODE) {
fsound->info.samplerate = fsinfo->samplerate;
fsound->info.channels = fsinfo->channels;
fsound->info.format = fsinfo->format;
if (fish_sound_set_format (fsound, fsinfo->format) == -1) {
fs_free (fsound);
return NULL;
}
}
return fsound;
}
long
fish_sound_flush (FishSound * fsound)
{
if (fsound == NULL) return -1;
if (fsound->codec && fsound->codec->flush)
return fsound->codec->flush (fsound);
return 0;
}
int
fish_sound_reset (FishSound * fsound)
{
if (fsound == NULL) return -1;
if (fsound->codec && fsound->codec->reset)
return fsound->codec->reset (fsound);
return 0;
}
FishSound *
fish_sound_delete (FishSound * fsound)
{
if (fsound == NULL) return NULL;
if (fsound->codec && fsound->codec->del)
fsound->codec->del (fsound);
fs_free (fsound->codec);
fish_sound_comments_free (fsound);
fs_free (fsound);
return NULL;
}
int
fish_sound_command (FishSound * fsound, int command, void * data, int datasize)
{
FishSoundInfo * fsinfo = (FishSoundInfo *)data;
int * pi = (int *)data;
if (fsound == NULL) return -1;
switch (command) {
case FISH_SOUND_GET_INFO:
memcpy (fsinfo, &fsound->info, sizeof (FishSoundInfo));
break;
case FISH_SOUND_GET_INTERLEAVE:
*pi = fsound->interleave;
break;
case FISH_SOUND_SET_INTERLEAVE:
fsound->interleave = (*pi ? 1 : 0);
break;
default:
if (fsound->codec && fsound->codec->command)
return fsound->codec->command (fsound, command, data, datasize);
break;
}
return 0;
}
int
fish_sound_get_interleave (FishSound * fsound)
{
if (fsound == NULL) return -1;
return fsound->interleave;
}
#ifndef FS_DISABLE_DEPRECATED
int
fish_sound_set_interleave (FishSound * fsound, int interleave)
{
if (fsound == NULL) return -1;
fsound->interleave = (interleave ? 1 : 0);
return 0;
}
#endif
long
fish_sound_get_frameno (FishSound * fsound)
{
if (fsound == NULL) return -1L;
return fsound->frameno;
}
int
fish_sound_set_frameno (FishSound * fsound, long frameno)
{
if (fsound == NULL) return -1;
fsound->frameno = frameno;
return 0;
}
int
fish_sound_prepare_truncation (FishSound * fsound, long next_granulepos,
int next_eos)
{
if (fsound == NULL) return -1;
fsound->next_granulepos = next_granulepos;
fsound->next_eos = next_eos;
return 0;
}

View File

@ -0,0 +1,594 @@
/*
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Organisation (CSIRO) Australia
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 name of CSIRO Australia nor the names of its
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 ORGANISATION 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.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "private.h"
/*#define DEBUG*/
static char *
fs_strdup (const char * s)
{
char * ret;
if (s == NULL) return NULL;
ret = fs_malloc (strlen(s) + 1);
return strcpy (ret, s);
}
static char *
fs_strdup_len (const char * s, int len)
{
char * ret;
if (s == NULL) return NULL;
if (len == 0) return NULL;
ret = fs_malloc (len + 1);
if (strncpy (ret, s, len) == NULL) {
fs_free (ret);
return NULL;
}
ret[len] = '\0';
return ret;
}
static char *
fs_index_len (const char * s, char c, int len)
{
int i;
for (i = 0; *s && i < len; i++, s++) {
if (*s == c) return (char *)s;
}
if (i < len) return (char *)s;
return NULL;
}
#if 0
static void comment_init(char **comments, int* length, char *vendor_string);
static void comment_add(char **comments, int* length, char *tag, char *val);
#endif
/*
Comments will be stored in the Vorbis style.
It is describled in the "Structure" section of
http://www.xiph.org/ogg/vorbis/doc/v-comment.html
The comment header is decoded as follows:
1) [vendor_length] = read an unsigned integer of 32 bits
2) [vendor_string] = read a UTF-8 vector as [vendor_length] octets
3) [user_comment_list_length] = read an unsigned integer of 32 bits
4) iterate [user_comment_list_length] times {
5) [length] = read an unsigned integer of 32 bits
6) this iteration's user comment = read a UTF-8 vector as [length] octets
}
7) [framing_bit] = read a single bit as boolean
8) if ( [framing_bit] unset or end of packet ) then ERROR
9) done.
If you have troubles, please write to ymnk@jcraft.com.
*/
#define readint(buf, base) (((buf[base+3]<<24)&0xff000000)| \
((buf[base+2]<<16)&0xff0000)| \
((buf[base+1]<<8)&0xff00)| \
(buf[base]&0xff))
#define writeint(buf, base, val) do{ buf[base+3]=((val)>>24)&0xff; \
buf[base+2]=((val)>>16)&0xff; \
buf[base+1]=((val)>>8)&0xff; \
buf[base]=(val)&0xff; \
}while(0)
#if 0
static void
comment_init(char **comments, int* length, char *vendor_string)
{
int vendor_length=strlen(vendor_string);
int user_comment_list_length=0;
int len=4+vendor_length+4;
char *p=(char*)fs_malloc(len);
if(p==NULL){
}
writeint(p, 0, vendor_length);
memcpy(p+4, vendor_string, vendor_length);
writeint(p, 4+vendor_length, user_comment_list_length);
*length=len;
*comments=p;
}
static void
comment_add(char **comments, int* length, char *tag, char *val)
{
char* p=*comments;
int vendor_length=readint(p, 0);
int user_comment_list_length=readint(p, 4+vendor_length);
int tag_len=(tag?strlen(tag):0);
int val_len=strlen(val);
int len=(*length)+4+tag_len+val_len;
p=(char*)fs_realloc(p, len);
if(p==NULL){
}
writeint(p, *length, tag_len+val_len); /* length of comment */
if(tag) memcpy(p+*length+4, tag, tag_len); /* comment */
memcpy(p+*length+4+tag_len, val, val_len); /* comment */
writeint(p, 4+vendor_length, user_comment_list_length+1);
*comments=p;
*length=len;
}
#endif
static int
fs_comment_validate_byname (const char * name, const char * value)
{
const char * c;
if (!name || !value) return 0;
for (c = name; *c; c++) {
if (*c < 0x20 || *c > 0x7D || *c == 0x3D) {
#ifdef DEBUG
printf ("XXX char %c in %s invalid\n", *c, name);
#endif
return 0;
}
}
/* XXX: we really should validate value as UTF-8 here, but ... */
return 1;
}
static FishSoundComment *
fs_comment_new (const char * name, const char * value)
{
FishSoundComment * comment;
if (!fs_comment_validate_byname (name, value)) return NULL;
comment = fs_malloc (sizeof (FishSoundComment));
comment->name = fs_strdup (name);
comment->value = fs_strdup (value);
return comment;
}
static void
fs_comment_free (FishSoundComment * comment)
{
if (!comment) return;
if (comment->name) fs_free (comment->name);
if (comment->value) fs_free (comment->value);
fs_free (comment);
}
static int
fs_comment_cmp (const FishSoundComment * comment1, const FishSoundComment * comment2)
{
if (comment1 == comment2) return 1;
if (!comment1 || !comment2) return 0;
if (strcasecmp (comment1->name, comment2->name)) return 0;
if (strcmp (comment1->value, comment2->value)) return 0;
return 1;
}
/* Public API */
const char *
fish_sound_comment_get_vendor (FishSound * fsound)
{
if (fsound == NULL) return NULL;
return fsound->vendor;
}
int
fish_sound_comment_set_vendor (FishSound * fsound, const char * vendor_string)
{
if (fsound == NULL) return FISH_SOUND_ERR_BAD;
if (fsound->vendor) fs_free (fsound->vendor);
fsound->vendor = fs_strdup (vendor_string);
return 0;
}
const FishSoundComment *
fish_sound_comment_first (FishSound * fsound)
{
if (fsound == NULL) return NULL;
return fs_vector_nth (fsound->comments, 0);
}
const FishSoundComment *
fish_sound_comment_first_byname (FishSound * fsound, char * name)
{
FishSoundComment * comment;
int i;
if (fsound == NULL) return NULL;
if (name == NULL) return fs_vector_nth (fsound->comments, 0);
if (!fs_comment_validate_byname (name, ""))
return NULL;
for (i = 0; i < fs_vector_size (fsound->comments); i++) {
comment = (FishSoundComment *) fs_vector_nth (fsound->comments, i);
if (comment->name && !strcasecmp (name, comment->name))
return comment;
}
return NULL;
}
const FishSoundComment *
fish_sound_comment_next (FishSound * fsound, const FishSoundComment * comment)
{
int i;
if (fsound == NULL || comment == NULL) return NULL;
i = fs_vector_find_index (fsound->comments, comment);
return fs_vector_nth (fsound->comments, i+1);
}
const FishSoundComment *
fish_sound_comment_next_byname (FishSound * fsound,
const FishSoundComment * comment)
{
FishSoundComment * v_comment;
int i;
if (fsound == NULL || comment == NULL) return NULL;
i = fs_vector_find_index (fsound->comments, comment);
for (i++; i < fs_vector_size (fsound->comments); i++) {
v_comment = (FishSoundComment *) fs_vector_nth (fsound->comments, i);
if (v_comment->name && !strcasecmp (comment->name, v_comment->name))
return v_comment;
}
return NULL;
}
#define _fs_comment_add(f,c) fs_vector_insert ((f)->comments, (c))
int
fish_sound_comment_add (FishSound * fsound, FishSoundComment * comment)
{
FishSoundComment * new_comment;
if (fsound == NULL) return FISH_SOUND_ERR_BAD;
if (fsound->mode != FISH_SOUND_ENCODE)
return FISH_SOUND_ERR_INVALID;
#if FS_ENCODE
if (!fs_comment_validate_byname (comment->name, comment->value))
return FISH_SOUND_ERR_COMMENT_INVALID;
new_comment = fs_comment_new (comment->name, comment->value);
_fs_comment_add (fsound, new_comment);
return 0;
#else
return FISH_SOUND_ERR_DISABLED;
#endif
}
int
fish_sound_comment_add_byname (FishSound * fsound, const char * name,
const char * value)
{
FishSoundComment * comment;
if (fsound == NULL) return FISH_SOUND_ERR_BAD;
if (fsound->mode != FISH_SOUND_ENCODE)
return FISH_SOUND_ERR_INVALID;
#if FS_ENCODE
if (!fs_comment_validate_byname (name, value))
return FISH_SOUND_ERR_COMMENT_INVALID;
comment = fs_comment_new (name, value);
_fs_comment_add (fsound, comment);
return 0;
#else
return FISH_SOUND_ERR_DISABLED;
#endif
}
int
fish_sound_comment_remove (FishSound * fsound, FishSoundComment * comment)
{
FishSoundComment * v_comment;
if (fsound == NULL) return FISH_SOUND_ERR_BAD;
if (fsound->mode != FISH_SOUND_ENCODE)
return FISH_SOUND_ERR_INVALID;
#if FS_ENCODE
v_comment = fs_vector_find (fsound->comments, comment);
if (v_comment == NULL) return 0;
fs_vector_remove (fsound->comments, v_comment);
fs_comment_free (v_comment);
return 1;
#else
return FISH_SOUND_ERR_DISABLED;
#endif
}
int
fish_sound_comment_remove_byname (FishSound * fsound, char * name)
{
FishSoundComment * comment;
int i, ret = 0;
if (fsound == NULL) return FISH_SOUND_ERR_BAD;
if (fsound->mode != FISH_SOUND_ENCODE)
return FISH_SOUND_ERR_INVALID;
#if FS_ENCODE
for (i = 0; i < fs_vector_size (fsound->comments); i++) {
comment = (FishSoundComment *) fs_vector_nth (fsound->comments, i);
if (!strcasecmp (name, comment->name)) {
fish_sound_comment_remove (fsound, comment);
i--;
ret++;
}
}
return ret;
#else
return FISH_SOUND_ERR_DISABLED;
#endif
}
/* Internal API */
int
fish_sound_comments_init (FishSound * fsound)
{
fsound->vendor = NULL;
fsound->comments = fs_vector_new ((FishSoundCmpFunc) fs_comment_cmp);
return 0;
}
int
fish_sound_comments_free (FishSound * fsound)
{
fs_vector_foreach (fsound->comments, (FishSoundFunc)fs_comment_free);
fs_vector_delete (fsound->comments);
fsound->comments = NULL;
if (fsound->vendor) fs_free (fsound->vendor);
fsound->vendor = NULL;
return 0;
}
int
fish_sound_comments_decode (FishSound * fsound, unsigned char * comments,
long length)
{
char *c= (char *)comments;
int len, i, nb_fields, n;
char *end;
char * name, * value, * nvalue = NULL;
FishSoundComment * comment;
if (length<8)
return -1;
end = c+length;
len=readint(c, 0);
c+=4;
if (c+len>end) return -1;
/* Vendor */
nvalue = fs_strdup_len (c, len);
fish_sound_comment_set_vendor (fsound, nvalue);
if (nvalue) fs_free (nvalue);
#ifdef DEBUG
fwrite(c, 1, len, stderr); fputc ('\n', stderr);
#endif
c+=len;
if (c+4>end) return -1;
nb_fields=readint(c, 0);
#ifdef DEBUG
printf ("fish_sound_comments_decode: %d comments\n", nb_fields);
#endif
c+=4;
for (i=0;i<nb_fields;i++)
{
if (c+4>end) return -1;
len=readint(c, 0);
#ifdef DEBUG
printf ("fish_sound_comments_decode: [%d] len %d\n", i, len);
#endif
c+=4;
if (c+len>end) return -1;
name = c;
value = fs_index_len (c, '=', len);
if (value) {
*value = '\0';
value++;
n = c+len - value;
nvalue = fs_strdup_len (value, n);
#ifdef DEBUG
printf ("fish_sound_comments_decode: %s -> %s (length %d)\n",
name, nvalue, n);
#endif
comment = fs_comment_new (name, nvalue);
_fs_comment_add (fsound, comment);
fs_free (nvalue);
} else {
#ifdef DEBUG
printf ("fish_sound_comments_decode: [%d] %s (no value)\n",
i, name, len);
#endif
nvalue = fs_strdup_len (name, len);
comment = fs_comment_new (nvalue, NULL);
_fs_comment_add (fsound, comment);
fs_free (nvalue);
}
c+=len;
}
#ifdef DEBUG
printf ("fish_sound_comments_decode: done\n");
#endif
return 0;
}
long
fish_sound_comments_encode (FishSound * fsound, unsigned char * buf,
long length)
{
char * c = (char *)buf;
const FishSoundComment * comment;
int nb_fields = 0, vendor_length, field_length;
long actual_length, remaining = length;
/* Vendor string */
vendor_length = strlen (fsound->vendor);
actual_length = 4 + vendor_length;
/* user comment list length */
actual_length += 4;
for (comment = fish_sound_comment_first (fsound); comment;
comment = fish_sound_comment_next (fsound, comment)) {
actual_length += 4 + strlen (comment->name); /* [size]"name" */
if (comment->value)
actual_length += 1 + strlen (comment->value); /* "=value" */
#ifdef DEBUG
printf ("fish_sound_comments_encode: %s = %s\n",
comment->name, comment->value);
#endif
nb_fields++;
}
actual_length++; /* framing bit */
if (buf == NULL) return actual_length;
remaining -= 4;
if (remaining <= 0) return actual_length;
writeint (c, 0, vendor_length);
c += 4;
field_length = strlen (fsound->vendor);
memcpy (c, fsound->vendor, MIN (field_length, remaining));
c += field_length; remaining -= field_length;
if (remaining <= 0 ) return actual_length;
remaining -= 4;
if (remaining <= 0) return actual_length;
writeint (c, 0, nb_fields);
c += 4;
for (comment = fish_sound_comment_first (fsound); comment;
comment = fish_sound_comment_next (fsound, comment)) {
field_length = strlen (comment->name); /* [size]"name" */
if (comment->value)
field_length += 1 + strlen (comment->value); /* "=value" */
remaining -= 4;
if (remaining <= 0) return actual_length;
writeint (c, 0, field_length);
c += 4;
field_length = strlen (comment->name);
memcpy (c, comment->name, MIN (field_length, remaining));
c += field_length; remaining -= field_length;
if (remaining <= 0) return actual_length;
if (comment->value) {
remaining --;
if (remaining <= 0) return actual_length;
*c = '=';
c++;
field_length = strlen (comment->value);
memcpy (c, comment->value, MIN (field_length, remaining));
c += field_length; remaining -= field_length;
if (remaining <= 0) return actual_length;
}
}
if (remaining <= 0) return actual_length;
*c = 0x01;
return actual_length;
}

View File

@ -0,0 +1,136 @@
/*
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Organisation (CSIRO) Australia
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 name of CSIRO Australia nor the names of its
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 ORGANISATION 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.
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include "private.h"
static int
fs_decode_update (FishSound * fsound, int interleave)
{
int ret = 0;
if (fsound->codec && fsound->codec->update)
ret = fsound->codec->update (fsound, interleave);
if (ret >= 0) {
fsound->interleave = interleave;
}
return ret;
}
int fish_sound_set_decoded_float (FishSound * fsound,
FishSoundDecoded_Float decoded,
void * user_data)
{
int ret = 0;
if (fsound == NULL) return -1;
#if FS_DECODE
ret = fs_decode_update (fsound, 0);
if (ret >= 0) {
fsound->callback.decoded_float = decoded;
fsound->user_data = user_data;
}
#else
return FISH_SOUND_ERR_DISABLED;
#endif
return ret;
}
int fish_sound_set_decoded_float_ilv (FishSound * fsound,
FishSoundDecoded_FloatIlv decoded,
void * user_data)
{
int ret = 0;
if (fsound == NULL) return -1;
#if FS_DECODE
ret = fs_decode_update (fsound, 1);
if (ret >= 0) {
fsound->callback.decoded_float_ilv = decoded;
fsound->user_data = user_data;
}
#else
return FISH_SOUND_ERR_DISABLED;
#endif
return ret;
}
long
fish_sound_decode (FishSound * fsound, unsigned char * buf, long bytes)
{
int format;
if (fsound == NULL) return -1;
#if FS_DECODE
if (fsound->info.format == FISH_SOUND_UNKNOWN) {
format = fish_sound_identify (buf, bytes);
if (format == FISH_SOUND_UNKNOWN) return -1;
fish_sound_set_format (fsound, format);
}
/*printf ("format: %s\n", fsound->codec->format->name);*/
if (fsound->codec && fsound->codec->decode)
return fsound->codec->decode (fsound, buf, bytes);
#else
return FISH_SOUND_ERR_DISABLED;
#endif
return 0;
}
/* DEPRECATED */
int fish_sound_set_decoded_callback (FishSound * fsound,
FishSoundDecoded_Float decoded,
void * user_data)
{
if (fsound == NULL) return -1;
return fsound->interleave ?
fish_sound_set_decoded_float_ilv (fsound, decoded, user_data) :
fish_sound_set_decoded_float (fsound, decoded, user_data);
}

View File

@ -0,0 +1,106 @@
/*
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Organisation (CSIRO) Australia
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 name of CSIRO Australia nor the names of its
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 ORGANISATION 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.
*/
#include "config.h"
#include <stdio.h>
#include <string.h>
#include "private.h"
int
fish_sound_set_encoded_callback (FishSound * fsound,
FishSoundEncoded encoded,
void * user_data)
{
if (fsound == NULL) return -1;
#if FS_ENCODE
fsound->callback.encoded = (void *)encoded;
fsound->user_data = user_data;
#else
return FISH_SOUND_ERR_DISABLED;
#endif
return 0;
}
long fish_sound_encode_float (FishSound * fsound, float * pcm[], long frames)
{
if (fsound == NULL) return -1;
#if FS_ENCODE
if (fsound->codec && fsound->codec->encode_f)
return fsound->codec->encode_f (fsound, pcm, frames);
#else
return FISH_SOUND_ERR_DISABLED;
#endif
return 0;
}
long fish_sound_encode_float_ilv (FishSound * fsound, float ** pcm,
long frames)
{
if (fsound == NULL) return -1;
#if FS_ENCODE
if (fsound->codec && fsound->codec->encode_f_ilv)
return fsound->codec->encode_f_ilv (fsound, pcm, frames);
#else
return FISH_SOUND_ERR_DISABLED;
#endif
return 0;
}
#ifndef FS_DISABLE_DEPRECATED
long
fish_sound_encode (FishSound * fsound, float ** pcm, long frames)
{
if (fsound == NULL) return -1;
#if FS_ENCODE
if (fsound->interleave) {
if (fsound->codec && fsound->codec->encode_f_ilv)
return fsound->codec->encode_f_ilv (fsound, pcm, frames);
} else {
if (fsound->codec && fsound->codec->encode_f)
return fsound->codec->encode_f (fsound, pcm, frames);
}
#else
return FISH_SOUND_ERR_DISABLED;
#endif
return 0;
}
#endif /* DEPRECATED */

View File

@ -0,0 +1,773 @@
/*
Copyright (C) 2007 Annodex Association
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 name of the Annodex Association nor the names of its
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 ASSOCIATION 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.
*/
/* Original patches by Tobias Gehrig, 2005
* http://www.annodex.net/software/libfishsound/libfishsound-flac/
*
* The Ogg FLAC mapping is documented in:
* http://flac.sourceforge.net/ogg_mapping.html
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "private.h"
#include "convert.h"
/*#define DEBUG*/
/*#define DEBUG_VERBOSE*/
#if HAVE_FLAC
#include "FLAC/all.h"
#define BITS_PER_SAMPLE 24
typedef struct _FishSoundFlacInfo {
FLAC__StreamDecoder *fsd;
FLAC__StreamEncoder *fse;
unsigned char * buffer;
char header;
long bufferlength;
unsigned long packetno;
struct {
unsigned char major, minor;
} version;
unsigned short header_packets;
void * ipcm;
#if FS_DECODE
float * pcm_out[8]; /* non-interleaved pcm, output (decode only);
* FLAC does max 8 channels */
#endif
#if FS_ENCODE
FLAC__StreamMetadata * enc_vc_metadata; /* FLAC metadata structure for
* vorbiscomments (encode only) */
#endif
} FishSoundFlacInfo;
int
fish_sound_flac_identify (unsigned char * buf, long bytes)
{
if (bytes < 8) return FISH_SOUND_UNKNOWN;
if (buf[0] != 0x7f) return FISH_SOUND_UNKNOWN;
if (!strncmp ((char *)buf+1, "FLAC", 4)) {
#ifdef DEBUG
printf("fish_sound_flac_identify: flac found\n");
#endif
/* if only a short buffer was passed, do a weak identify */
if (bytes == 8) return FISH_SOUND_FLAC;
/* otherwise, look for the fLaC header preceding STREAMINFO */
if (!strncmp ((char *)buf+9, "fLaC", 4)) {
return FISH_SOUND_FLAC;
}
}
return FISH_SOUND_UNKNOWN;
}
static int
fs_flac_command (FishSound * fsound, int command, void * data, int datasize)
{
return 0;
}
#if FS_DECODE
static FLAC__StreamDecoderReadStatus
fs_flac_read_callback(const FLAC__StreamDecoder *decoder,
FLAC__byte buffer[], unsigned *bytes,
void *client_data)
{
FishSound* fsound = (FishSound*)client_data;
FishSoundFlacInfo* fi = (FishSoundFlacInfo *)fsound->codec_data;
#ifdef DEBUG_VERBOSE
printf("fs_flac_read_callback: IN\n");
#endif
if (fi->bufferlength > *bytes) {
#ifdef DEBUG
printf("fs_flac_read_callback: too much data\n");
#endif
return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
} else if (fi->bufferlength < 1) {
#ifdef DEBUG
printf("fs_flac_read_callback: no data, %ld\n",fi->bufferlength);
#endif
return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM;
}
memcpy(buffer, fi->buffer, fi->bufferlength);
*bytes = fi->bufferlength;
fi->bufferlength = 0;
return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
}
static FLAC__StreamDecoderWriteStatus
fs_flac_write_callback(const FLAC__StreamDecoder *decoder,
const FLAC__Frame *frame,
const FLAC__int32 * const buffer[],
void *client_data)
{
FishSound* fsound = (FishSound*)client_data;
FishSoundFlacInfo* fi = (FishSoundFlacInfo *)fsound->codec_data;
int i, j, channels, blocksize, offset;
channels = frame->header.channels;
blocksize = frame->header.blocksize;
#ifdef DEBUG_VERBOSE
printf("fs_flac_write_callback: IN, blocksize %d\n", blocksize);
#endif
fsound->frameno += blocksize;
if (fsound->callback.decoded_float) {
float norm = 1.0 / ((1 << (frame->header.bits_per_sample - 1)));
if (fsound->interleave) {
FishSoundDecoded_FloatIlv dfi;
float* retpcm;
fi->ipcm = realloc(fi->ipcm, sizeof(float) * channels * blocksize);
retpcm = (float*) fi->ipcm;
for (i = 0; i < blocksize; i++) {
offset = i * channels;
for (j = 0; j < channels; j++)
retpcm[offset + j] = buffer[j][i] * norm;
}
dfi = (FishSoundDecoded_FloatIlv)fsound->callback.decoded_float_ilv;
dfi (fsound, (float **)retpcm, blocksize, fsound->user_data);
} else {
FishSoundDecoded_Float df;
FLAC__int32 * s = (FLAC__int32 *)buffer; /* de-interleave source */
float *d; /* de-interleave dest */
for (j = 0; j < channels; j++) {
fi->pcm_out[j] = realloc(fi->pcm_out[j], sizeof(float) * blocksize);
}
for (i = 0; i < blocksize; i++)
for (j = 0; j < channels; j++) {
d = fi->pcm_out[j];
d[i] = s[i*channels + j] * norm;
}
df = (FishSoundDecoded_Float)fsound->callback.decoded_float;
df (fsound, fi->pcm_out, blocksize, fsound->user_data);
}
}
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
static void
fs_flac_meta_callback(const FLAC__StreamDecoder *decoder,
const FLAC__StreamMetadata *metadata,
void *client_data)
{
FishSound* fsound = (FishSound*)client_data;
/* FishSoundFlacInfo* fi = (FishSoundFlacInfo *)fsound->codec_data; */
#ifdef DEBUG
printf("fs_flac_meta_callback: IN\n");
#endif
switch (metadata->type) {
case FLAC__METADATA_TYPE_STREAMINFO:
#ifdef DEBUG
printf("fs_flac_meta_callback: channels %d, samplerate %d\n",
metadata->data.stream_info.channels,
metadata->data.stream_info.sample_rate);
#endif
fsound->info.channels = metadata->data.stream_info.channels;
fsound->info.samplerate = metadata->data.stream_info.sample_rate;
break;
default:
#ifdef DEBUG
printf("fs_flac_meta_callback: not yet implemented type\n");
#endif
break;
}
}
static void
fs_flac_error_callback(const FLAC__StreamDecoder *decoder,
FLAC__StreamDecoderErrorStatus status,
void *client_data)
{
#ifdef DEBUG
printf("fs_flac_error_callback: IN\n");
#endif
fprintf(stderr, "FLAC ERROR: %s\n", FLAC__StreamDecoderErrorStatusString[status]);
}
#endif
#if FS_DECODE
static void*
fs_flac_decode_header (FishSound * fsound, unsigned char *buf, long bytes)
{
FishSoundFlacInfo *fi = fsound->codec_data;
if (buf[0] != 0x7f) return NULL;
if (strncmp((char *)buf+1, "FLAC", 4) != 0) return NULL;
fi->version.major = buf[5];
fi->version.minor = buf[6];
#ifdef DEBUG
printf("fs_flac_decode_header : Flac Ogg Mapping Version: %d.%d\n",
fi->version.major, fi->version.minor);
#endif
fi->header_packets = buf[7] << 8 | buf[8];
#ifdef DEBUG
printf("fs_flac_decode_header: Number of Header packets: %d\n",
fi->header_packets);
#endif
if ((fi->fsd = FLAC__stream_decoder_new()) == NULL) {
#ifdef DEBUG
printf ("fs_flac_decode_header: unable to create new stream_decoder\n");
#endif
return NULL;
}
FLAC__stream_decoder_set_read_callback(fi->fsd, fs_flac_read_callback);
FLAC__stream_decoder_set_write_callback(fi->fsd, fs_flac_write_callback);
FLAC__stream_decoder_set_metadata_callback(fi->fsd, fs_flac_meta_callback);
FLAC__stream_decoder_set_error_callback(fi->fsd, fs_flac_error_callback);
FLAC__stream_decoder_set_client_data(fi->fsd, fsound);
if (FLAC__stream_decoder_init(fi->fsd) != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
return NULL;
return fi->fsd;
}
static long
fs_flac_decode (FishSound * fsound, unsigned char * buf, long bytes)
{
FishSoundFlacInfo *fi = fsound->codec_data;
#ifdef DEBUG_VERBOSE
printf("fs_flac_decode: IN, fi->packetno = %ld\n", fi->packetno);
#endif
if (fi->packetno == 0) {
if (fs_flac_decode_header (fsound, buf, bytes) == NULL) {
#ifdef DEBUG
printf("fs_flac_decode: Error reading header\n");
#endif
return -1;
}
fi->buffer = fs_malloc(sizeof(unsigned char)*bytes);
memcpy(fi->buffer, buf+9, bytes-9);
fi->bufferlength = bytes-9;
}
else if (fi->packetno <= fi->header_packets){
unsigned char* tmp = fs_malloc(sizeof(unsigned char)*(fi->bufferlength+bytes));
#ifdef DEBUG
printf("fs_flac_decode: handling header (fi->header_packets = %d)\n",
fi->header_packets);
#endif
#if 0
if (fi->packetno == 1) fish_sound_comments_decode (fsound, buf, bytes);
#endif
if ((buf[0] & 0x7) == 4) {
int len = (buf[1]<<16) + (buf[2]<<8) + buf[3];
#ifdef DEBUG
printf ("fs_flac_decode: got vorbiscomments len %d\n", len);
#endif
fish_sound_comments_decode (fsound, buf+4, len);
}
memcpy(tmp, fi->buffer, fi->bufferlength);
memcpy(tmp+fi->bufferlength, buf, bytes);
fi->bufferlength += bytes;
fs_free(fi->buffer);
fi->buffer = tmp;
if (fi->packetno == fi->header_packets) {
FLAC__stream_decoder_process_until_end_of_metadata(fi->fsd);
fs_free(fi->buffer);
}
} else {
fi->buffer = buf;
fi->bufferlength = bytes;
FLAC__stream_decoder_process_single(fi->fsd);
}
fi->packetno++;
return 0;
}
#else /* !FS_DECODE */
#define fs_flac_decode NULL
#endif
#if FS_ENCODE
static FLAC__StreamEncoderWriteStatus
fs_flac_enc_write_callback(const FLAC__StreamEncoder *encoder,
const FLAC__byte buffer[], unsigned bytes,
unsigned samples, unsigned current_frame,
void *client_data)
{
FishSound* fsound = (FishSound*)client_data;
FishSoundFlacInfo *fi = fsound->codec_data;
#ifdef DEBUG
printf("fs_flac_enc_write_callback: IN\n");
printf("fs_flac_enc_write_callback: bytes: %d, samples: %d\n", bytes, samples);
#endif
if (fsound->callback.encoded) {
FishSoundEncoded encoded = (FishSoundEncoded) fsound->callback.encoded;
if (fi->packetno == 0 && fi->header <= 1) {
if (fi->header == 0) {
/* libFLAC has called us with data containing the normal fLaC header
* and a STREAMINFO block. Prepend the FLAC Ogg mapping header,
* as described in http://flac.sourceforge.net/ogg_mapping.html.
*/
#ifdef DEBUG
printf("fs_flac_enc_write_callback: generating FLAC header packet: "
"%c%c%c%c\n", buffer[0], buffer[1], buffer[2], buffer[3]);
#endif
fi->buffer = (unsigned char*)malloc(sizeof(unsigned char)*(bytes+9));
fi->buffer[0] = 0x7f;
fi->buffer[1] = 0x46; /* 'F' */
fi->buffer[2] = 0x4c; /* 'L' */
fi->buffer[3] = 0x41; /* 'A' */
fi->buffer[4] = 0x43; /* 'C' */
fi->buffer[5] = 1; /* Version major generated by this file */
fi->buffer[6] = 0; /* Version minor generated by this file */
fi->buffer[7] = 0; /* MSB(be): Nr. other non-audio header packets */
fi->buffer[8] = 1; /* LSB(be): Nr. other non-audio header packets */
memcpy (fi->buffer+9, buffer, bytes); /* fLaC header ++ STREAMINFO */
fi->bufferlength = bytes+9;
fi->header++;
} else {
/* Make a temporary copy of the metadata header to pass to the user
* callback.
*/
unsigned char* tmp = (unsigned char*)malloc(sizeof(unsigned char)*(bytes+fi->bufferlength));
memcpy (tmp, fi->buffer, fi->bufferlength);
memcpy (tmp+fi->bufferlength, buffer, bytes);
fs_free(fi->buffer);
fi->buffer = tmp;
fi->bufferlength += bytes;
fi->header++;
encoded (fsound, (unsigned char *)fi->buffer, (long)fi->bufferlength,
fsound->user_data);
}
} else {
fsound->frameno += samples;
encoded (fsound, (unsigned char *)buffer, (long)bytes,
fsound->user_data);
}
}
return FLAC__STREAM_ENCODER_WRITE_STATUS_OK;
}
static void
fs_flac_enc_meta_callback(const FLAC__StreamEncoder *encoder,
const FLAC__StreamMetadata *metadata,
void *client_data)
{
/* FishSound* fsound = (FishSound*)client_data; */
/* FishSoundFlacInfo* fi = (FishSoundFlacInfo *)fsound->codec_data; */
#ifdef DEBUG
printf("fs_flac_enc_meta_callback: IN\n");
#endif
switch (metadata->type) {
case FLAC__METADATA_TYPE_STREAMINFO:
#ifdef DEBUG
printf("fs_flac_enc_meta_callback: channels %d, samplerate %d\n",
metadata->data.stream_info.channels,
metadata->data.stream_info.sample_rate);
#endif
/*
fsound->info.channels = metadata->data.stream_info.channels;
fsound->info.samplerate = metadata->data.stream_info.sample_rate;
*/
break;
default:
#ifdef DEBUG
printf("fs_flac_enc_meta_callback: metadata type not yet implemented\n");
#endif
break;
}
return;
}
/* Create a local alias for an unwieldy type name */
typedef FLAC__StreamMetadata_VorbisComment_Entry FLAC__VCEntry;
static void
fs_flac_metadata_free (FLAC__StreamMetadata * metadata)
{
unsigned int i, length;
FLAC__VCEntry * comments;
if (metadata == NULL) return;
length = metadata->data.vorbis_comment.num_comments;
comments = metadata->data.vorbis_comment.comments;
for (i = 0; i < length; i++) {
fs_free (comments[i].entry);
}
fs_free (comments);
fs_free (metadata);
return;
}
static FLAC__byte *
fs_flac_encode_vcentry (const FishSoundComment * comment)
{
FLAC__byte * entry;
FLAC__uint32 length;
size_t name_len=0, value_len=0;
name_len = strlen(comment->name);
length = name_len + 1;
if (comment->value) {
value_len = strlen (comment->value);
length += value_len + 1;
}
entry = fs_malloc (length);
/* We assume that comment->name, value are NUL terminated, as they were
* produced by our own comments.c */
strcpy ((char *)entry, comment->name);
if (comment->value) {
entry[name_len] = '=';
strcpy ((char *)&entry[name_len+1], comment->value);
}
entry[length-1] = '\0';
return entry;
}
static FLAC__StreamMetadata *
fs_flac_encode_vorbiscomments (FishSound * fsound)
{
FishSoundFlacInfo * fi = fsound->codec_data;
FLAC__StreamMetadata * metadata;
const FishSoundComment * comment;
unsigned int i=0, length=0, total_length;
FLAC__VCEntry * comments;
/* libFLAC seems to require us to know the total length of the generated
* vorbiscomment packet, even though it will silently generate the
* vendor string. Hence, this value was determined by inspection for
* the version "reference libFLAC 1.1.2"
*/
total_length = 40;
/* Count the number of comments */
for (comment = fish_sound_comment_first (fsound); comment;
comment = fish_sound_comment_next (fsound, comment)) {
length++;
}
if (length == 0) return NULL;
comments = (FLAC__VCEntry *)fs_malloc (sizeof(FLAC__VCEntry) * length);
for (comment = fish_sound_comment_first (fsound); comment;
comment = fish_sound_comment_next (fsound, comment)) {
comments[i].entry = fs_flac_encode_vcentry (comment);
comments[i].length = strlen((char *)comments[i].entry);
/* In the generated vorbiscomment data, each entry is preceded by a
* 32bit length specifier. */
total_length += 4 + comments[i].length;
i++;
}
metadata = (FLAC__StreamMetadata *) fs_malloc (sizeof (*metadata));
metadata->type = FLAC__METADATA_TYPE_VORBIS_COMMENT;
metadata->is_last = true;
metadata->length = total_length;
/* Don't bother setting the vendor_string, as libFLAC ignores it */
metadata->data.vorbis_comment.num_comments = length;
metadata->data.vorbis_comment.comments = comments;
/* Remember the allocated metadata */
fi->enc_vc_metadata = metadata;
return metadata;
}
static FishSound *
fs_flac_enc_headers (FishSound * fsound)
{
FishSoundFlacInfo * fi = fsound->codec_data;
FLAC__StreamMetadata * metadata;
fi->fse = FLAC__stream_encoder_new();
FLAC__stream_encoder_set_channels(fi->fse, fsound->info.channels);
FLAC__stream_encoder_set_sample_rate(fi->fse, fsound->info.samplerate);
FLAC__stream_encoder_set_bits_per_sample(fi->fse, BITS_PER_SAMPLE);
FLAC__stream_encoder_set_write_callback(fi->fse, fs_flac_enc_write_callback);
FLAC__stream_encoder_set_metadata_callback(fi->fse, fs_flac_enc_meta_callback);
FLAC__stream_encoder_set_client_data(fi->fse, fsound);
metadata = fs_flac_encode_vorbiscomments (fsound);
if (metadata != NULL)
FLAC__stream_encoder_set_metadata (fi->fse, &metadata, 1);
/* FLAC__stream_encoder_set_total_samples_estimate(fi->fse, ...);*/
if (FLAC__stream_encoder_init(fi->fse) != FLAC__STREAM_ENCODER_OK)
return NULL;
return fsound;
}
static long
fs_flac_encode_f (FishSound * fsound, float * pcm[], long frames)
{
FishSoundFlacInfo *fi = fsound->codec_data;
FLAC__int32 *buffer;
float * p, norm = (1 << (BITS_PER_SAMPLE - 1));
long i;
int j, channels = fsound->info.channels;
#ifdef DEBUG
printf("fs_flac_encode_f: IN, frames = %ld\n", frames);
#endif
fi->ipcm = realloc(fi->ipcm, sizeof(FLAC__int32) * channels * frames);
buffer = (FLAC__int32*) fi->ipcm;
for (i = 0; i < frames; i++) {
for (j = 0; j < channels; j++) {
p = pcm[j];
buffer[i*channels + j] = (FLAC__int32) (p[i] * norm);
}
}
if (fi->packetno == 0)
fs_flac_enc_headers (fsound);
/* We could have used FLAC__stream_encoder_process() and a more direct
* conversion loop above, rather than converting and interleaving. */
FLAC__stream_encoder_process_interleaved(fi->fse, buffer, frames);
fi->packetno++;
return frames;
}
static long
fs_flac_encode_f_ilv (FishSound * fsound, float ** pcm, long frames)
{
FishSoundFlacInfo *fi = fsound->codec_data;
FLAC__int32 *buffer;
float * p = (float*)pcm, norm = (1 << (BITS_PER_SAMPLE - 1));
long i, length = frames * fsound->info.channels;
#ifdef DEBUG
printf("fs_flac_encode_f_ilv: IN, frames = %ld\n", frames);
#endif
fi->ipcm = realloc(fi->ipcm, sizeof(FLAC__int32)*fsound->info.channels*frames);
buffer = (FLAC__int32*) fi->ipcm;
for (i=0; i<length; i++)
buffer[i] = p[i] * norm;
if (fi->packetno == 0)
fs_flac_enc_headers (fsound);
FLAC__stream_encoder_process_interleaved(fi->fse, buffer, frames);
fi->packetno++;
return frames;
}
#else /* ! FS_ENCODE */
#define fs_flac_encode_f NULL
#define fs_flac_encode_f_ilv NULL
#endif /* ! FS_ENCODE */
static FishSound *
fs_flac_delete (FishSound * fsound)
{
FishSoundFlacInfo * fi = (FishSoundFlacInfo *)fsound->codec_data;
int i;
#ifdef DEBUG
printf("fs_flac_delete: IN\n");
#endif
if (fsound->mode == FISH_SOUND_DECODE) {
if (fi->fsd) {
FLAC__stream_decoder_finish(fi->fsd);
FLAC__stream_decoder_delete(fi->fsd);
}
} else if (fsound->mode == FISH_SOUND_ENCODE) {
if (fi->fse) {
FLAC__stream_encoder_finish(fi->fse);
FLAC__stream_encoder_delete(fi->fse);
}
if (fi->buffer) {
fs_free(fi->buffer);
fi->buffer = NULL;
}
}
if (fi->ipcm) fs_free(fi->ipcm);
for (i = 0; i < 8; i++) {
if (fi->pcm_out[i]) fs_free (fi->pcm_out[i]);
}
#if FS_ENCODE
if (fi->enc_vc_metadata) {
fs_flac_metadata_free (fi->enc_vc_metadata);
}
#endif
fs_free (fi);
fsound->codec_data = NULL;
return fsound;
}
static int
fs_flac_update (FishSound * fsound, int interleave)
{
return 0;
}
static int
fs_flac_reset (FishSound * fsound)
{
/*FishSoundFlacInfo * fi = (FishSoundFlacInfo *)fsound->codec_data;*/
#if 0
if (fsound->mode == FISH_SOUND_DECODE) {
FLAC__stream_decoder_reset(fi->fsd);
} else if (fsound->mode == FISH_SOUND_ENCODE) {
}
#endif
return 0;
}
static long
fs_flac_flush (FishSound * fsound)
{
FishSoundFlacInfo * fi = (FishSoundFlacInfo *)fsound->codec_data;
#ifdef DEBUG
printf("fs_flac_flush: IN (%s)\n",
fsound->mode == FISH_SOUND_DECODE ? "decode" : "encode");
#endif
if (fsound->mode == FISH_SOUND_DECODE) {
FLAC__stream_decoder_finish(fi->fsd);
} else if (fsound->mode == FISH_SOUND_ENCODE) {
FLAC__stream_encoder_finish(fi->fse);
}
return 0;
}
static FishSound *
fs_flac_init (FishSound * fsound)
{
FishSoundFlacInfo *fi;
int i;
fi = fs_malloc (sizeof (FishSoundFlacInfo));
if (fi == NULL) return NULL;
fi->fsd = NULL;
fi->fse = NULL;
fi->buffer = NULL;
fi->packetno = 0;
fi->header = 0;
fi->header_packets = 0;
fi->ipcm = NULL;
for (i = 0; i < 8; i++) {
fi->pcm_out[i] = NULL;
}
#if FS_ENCODE
fi->enc_vc_metadata = NULL;
#endif
fsound->codec_data = fi;
return fsound;
}
FishSoundCodec *
fish_sound_flac_codec (void)
{
FishSoundCodec * codec;
codec = (FishSoundCodec *) fs_malloc (sizeof (FishSoundCodec));
codec->format.format = FISH_SOUND_FLAC;
codec->format.name = "Flac (Xiph.Org)";
codec->format.extension = "ogg";
codec->init = fs_flac_init;
codec->del = fs_flac_delete;
codec->reset = fs_flac_reset;
codec->update = fs_flac_update;
codec->command = fs_flac_command;
codec->decode = fs_flac_decode;
codec->encode_f = fs_flac_encode_f;
codec->encode_f_ilv = fs_flac_encode_f_ilv;
codec->flush = fs_flac_flush;
return codec;
}
#else /* !HAVE_FLAC */
int
fish_sound_flac_identify (unsigned char * buf, long bytes)
{
return FISH_SOUND_UNKNOWN;
}
FishSoundCodec *
fish_sound_flac_codec (void)
{
return NULL;
}
#endif

View File

@ -0,0 +1,730 @@
/*
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Organisation (CSIRO) Australia
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 name of CSIRO Australia nor the names of its
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 ORGANISATION 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.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "private.h"
#include "convert.h"
/*#define DEBUG*/
#if HAVE_SPEEX
#if HAVE_SPEEX_1_1
#include <speex/speex.h>
#include <speex/speex_header.h>
#include <speex/speex_stereo.h>
#include <speex/speex_callbacks.h>
#else /* Speex 1.0 */
#include <speex.h>
#include <speex_header.h>
#include <speex_stereo.h>
#include <speex_callbacks.h>
#endif
/* Format for the vendor string: "Encoded with Speex VERSION", where VERSION
* is the libspeex version as read from a newly-generated Speex header.
*/
#define VENDOR_FORMAT "Encoded with Speex %s"
#define DEFAULT_ENH_ENABLED 1
#define MAX_FRAME_BYTES 2000
typedef struct _FishSoundSpeexEnc {
int frame_offset; /* number of speex frames done in this packet */
int pcm_offset;
char cbits[MAX_FRAME_BYTES];
int id;
} FishSoundSpeexEnc;
typedef struct _FishSoundSpeexInfo {
int packetno;
void * st;
SpeexBits bits;
int frame_size;
int nframes;
int extra_headers;
SpeexStereoState stereo;
int pcm_len; /* nr frames in pcm */
float * ipcm; /* interleaved pcm */
float * pcm[2]; /* Speex does max 2 channels */
FishSoundSpeexEnc * enc;
} FishSoundSpeexInfo;
int
fish_sound_speex_identify (unsigned char * buf, long bytes)
{
SpeexHeader * header;
if (bytes < 8) return FISH_SOUND_UNKNOWN;
if (!strncmp ((char *)buf, "Speex ", 8)) {
/* if only a short buffer was passed, do a weak identify */
if (bytes == 8) return FISH_SOUND_SPEEX;
/* otherwise, assume the buffer is an entire initial header and
* feed it to speex_packet_to_header() */
if ((header = speex_packet_to_header ((char *)buf, (int)bytes)) != NULL) {
fs_free(header);
return FISH_SOUND_SPEEX;
}
}
return FISH_SOUND_UNKNOWN;
}
static int
fs_speex_command (FishSound * fsound, int command, void * data, int datasize)
{
return 0;
}
#if FS_DECODE
static void *
process_header(unsigned char * buf, long bytes, int enh_enabled,
int * frame_size, int * rate,
int * nframes, int forceMode, int * channels,
SpeexStereoState * stereo, int * extra_headers)
{
void *st;
SpeexMode *mode;
SpeexHeader *header;
int modeID;
SpeexCallback callback;
header = speex_packet_to_header((char*)buf, (int)bytes);
if (!header) {
/*info_dialog_new ("Speex error", NULL, "Speex: cannot read header");*/
return NULL;
}
if (header->mode >= SPEEX_NB_MODES || header->mode < 0) {
/*
info_dialog_new ("Speex error", NULL,
"Mode number %d does not (any longer) exist in this version\n",
header->mode);
*/
return NULL;
}
modeID = header->mode;
if (forceMode!=-1)
modeID = forceMode;
/* speex_mode_list[] is declared const in speex 1.1.x, hence the cast */
mode = (SpeexMode *)speex_mode_list[modeID];
if (header->speex_version_id > 1) {
/*
info_dialog_new ("Speex error", NULL,
"This file was encoded with Speex bit-stream version %d, "
"which I don't know how to decode\n",
header->speex_version_id);
*/
return NULL;
}
if (mode->bitstream_version < header->mode_bitstream_version) {
/*
info_dialog_new ("Speex error", NULL,
"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 > header->mode_bitstream_version) {
/*
info_dialog_new ("Speex error", NULL,
"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) {
/*
info_dialog_new ("Speex error", NULL,
"Decoder initialization failed.\n");
*/
return NULL;
}
speex_decoder_ctl(st, SPEEX_SET_ENH, &enh_enabled);
speex_decoder_ctl(st, SPEEX_GET_FRAME_SIZE, frame_size);
if (!(*channels==1))
{
callback.callback_id = SPEEX_INBAND_STEREO;
callback.func = speex_std_stereo_request_handler;
callback.data = stereo;
speex_decoder_ctl(st, SPEEX_SET_HANDLER, &callback);
}
if (!*rate)
*rate = header->rate;
/* Adjust rate if --force-* options are used */
if (forceMode!=-1)
{
if (header->mode < forceMode)
*rate <<= (forceMode - header->mode);
if (header->mode > forceMode)
*rate >>= (header->mode - forceMode);
}
speex_decoder_ctl(st, SPEEX_SET_SAMPLING_RATE, rate);
*nframes = header->frames_per_packet;
if (*channels == -1)
*channels = header->nb_channels;
#ifdef DEBUG
fprintf (stderr, "Decoding %d Hz audio using %s mode",
*rate, mode->modeName);
if (*channels==1)
fprintf (stderr, " (mono");
else
fprintf (stderr, " (stereo");
if (header->vbr)
fprintf (stderr, " (VBR)\n");
else
fprintf(stderr, "\n");
#endif
*extra_headers = header->extra_headers;
fs_free(header);
return st;
}
static int
fs_speex_free_buffers (FishSound * fsound)
{
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
if (fsound->mode == FISH_SOUND_DECODE) {
if (fss->ipcm && fss->ipcm != fss->pcm[0]) fs_free (fss->ipcm);
if (fss->pcm[0]) fs_free (fss->pcm[0]);
if (fss->pcm[1]) fs_free (fss->pcm[1]);
} else {
if (fss->ipcm) fs_free (fss->ipcm);
}
return 0;
}
static inline int
fs_speex_float_dispatch (FishSound * fsound)
{
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
FishSoundDecoded_FloatIlv df;
FishSoundDecoded_Float dfi;
int retval;
if (fsound->interleave) {
dfi = (FishSoundDecoded_FloatIlv)fsound->callback.decoded_float_ilv;
retval = dfi (fsound, (float **)fss->ipcm, fss->frame_size,
fsound->user_data);
} else {
df = (FishSoundDecoded_Float)fsound->callback.decoded_float;
retval = df (fsound, fss->pcm, fss->frame_size, fsound->user_data);
}
return retval;
}
static long
fs_speex_decode (FishSound * fsound, unsigned char * buf, long bytes)
{
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
int enh_enabled = DEFAULT_ENH_ENABLED;
int rate = 0;
int channels = -1;
int forceMode = -1;
int i, j;
if (fss->packetno == 0) {
fss->st = process_header (buf, bytes, enh_enabled,
&fss->frame_size, &rate,
&fss->nframes, forceMode, &channels,
&fss->stereo,
&fss->extra_headers);
if (fss->st == NULL) {
/* XXX: error */
}
#ifdef DEBUG
printf ("speex: got %d channels, %d Hz\n", channels, rate);
#endif
fsound->info.samplerate = rate;
fsound->info.channels = channels;
fss->ipcm = fs_malloc (sizeof (float) * fss->frame_size * channels);
if (channels == 1) {
fss->pcm[0] = fss->ipcm;
} else if (channels == 2) {
fss->pcm[0] = fs_malloc (sizeof (float) * fss->frame_size);
fss->pcm[1] = fs_malloc (sizeof (float) * fss->frame_size);
}
if (fss->nframes == 0) fss->nframes = 1;
} else if (fss->packetno == 1) {
/* Comments */
fish_sound_comments_decode (fsound, buf, bytes);
} else if (fss->packetno <= 1+fss->extra_headers) {
/* Unknown extra headers */
} else {
speex_bits_read_from (&fss->bits, (char *)buf, (int)bytes);
for (i = 0; i < fss->nframes; i++) {
/* Decode frame */
speex_decode (fss->st, &fss->bits, fss->ipcm);
if (fsound->info.channels == 2) {
speex_decode_stereo (fss->ipcm, fss->frame_size, &fss->stereo);
if (fsound->interleave) {
for (j = 0; j < fss->frame_size * fsound->info.channels; j++) {
fss->ipcm[j] /= 32767.0;
}
} else {
_fs_deinterleave ((float **)fss->ipcm, fss->pcm,
fss->frame_size, 2, (float)(1/32767.0));
}
} else {
for (j = 0; j < fss->frame_size; j++) {
fss->ipcm[j] /= 32767.0;
}
}
fsound->frameno += fss->frame_size;
fs_speex_float_dispatch (fsound);
}
}
fss->packetno++;
return 0;
}
#else /* !FS_DECODE */
#define fs_speex_decode NULL
#endif
#if FS_ENCODE
static FishSound *
fs_speex_enc_headers (FishSound * fsound)
{
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
SpeexMode * mode = NULL;
SpeexHeader header;
unsigned char * buf;
int bytes;
size_t buflen;
/* XXX: set wb, nb, uwb modes */
/* These modes are declared const in speex 1.1.x, hence the explicit cast */
mode = (SpeexMode *)&speex_wb_mode;
speex_init_header (&header, fsound->info.samplerate, 1, mode);
header.frames_per_packet = fss->nframes; /* XXX: frames per packet */
header.vbr = 1; /* XXX: VBR */
header.nb_channels = fsound->info.channels;
fss->st = speex_encoder_init (mode);
if (fsound->callback.encoded) {
FishSoundEncoded encoded = (FishSoundEncoded)fsound->callback.encoded;
char vendor_string[128];
/* header */
buf = (unsigned char *) speex_header_to_packet (&header, &bytes);
encoded (fsound, buf, (long)bytes, fsound->user_data);
fss->packetno++;
fs_free (buf);
/* comments */
snprintf (vendor_string, 128, VENDOR_FORMAT, header.speex_version);
fish_sound_comment_set_vendor (fsound, vendor_string);
bytes = fish_sound_comments_encode (fsound, NULL, 0);
buf = fs_malloc (bytes);
bytes = fish_sound_comments_encode (fsound, buf, bytes);
encoded (fsound, buf, (long)bytes, fsound->user_data);
fss->packetno++;
fs_free (buf);
}
speex_encoder_ctl (fss->st, SPEEX_SET_SAMPLING_RATE,
&fsound->info.samplerate);
speex_encoder_ctl (fss->st, SPEEX_GET_FRAME_SIZE, &fss->frame_size);
#ifdef DEBUG
printf ("got frame size %d\n", fss->frame_size);
#endif
/* XXX: blah blah blah ... set VBR etc. */
buflen = fss->frame_size * fsound->info.channels * sizeof (float);
fss->ipcm = fs_malloc (buflen);
memset (fss->ipcm, 0, buflen);
return fsound;
}
static long
fs_speex_encode_write (FishSound * fsound)
{
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
FishSoundSpeexEnc * fse = (FishSoundSpeexEnc *)fss->enc;
int bytes;
speex_bits_insert_terminator (&fss->bits);
bytes = speex_bits_write (&fss->bits, fse->cbits, MAX_FRAME_BYTES);
speex_bits_reset (&fss->bits);
if (fsound->callback.encoded) {
FishSoundEncoded encoded = (FishSoundEncoded)fsound->callback.encoded;
encoded (fsound, (unsigned char *)fse->cbits, (long)bytes,
fsound->user_data);
}
return bytes;
}
static long
fs_speex_encode_block (FishSound * fsound)
{
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
FishSoundSpeexEnc * fse = (FishSoundSpeexEnc *)fss->enc;
long nencoded = fse->pcm_offset;
if (fsound->info.channels == 2)
speex_encode_stereo (fss->ipcm, fse->pcm_offset, &fss->bits);
speex_encode (fss->st, fss->ipcm, &fss->bits);
fsound->frameno += fse->pcm_offset;
fse->frame_offset++;
if (fse->frame_offset == fss->nframes) {
fs_speex_encode_write (fsound);
fse->frame_offset = 0;
}
fse->pcm_offset = 0;
return nencoded;
}
static long
fs_speex_encode_f_ilv (FishSound * fsound, float ** pcm, long frames)
{
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
FishSoundSpeexEnc * fse = (FishSoundSpeexEnc *)fss->enc;
long remaining = frames, len, nencoded = 0;
int j, start, end;
int channels = fsound->info.channels;
float * p = (float *)pcm;
if (fss->packetno == 0)
fs_speex_enc_headers (fsound);
while (remaining > 0) {
len = MIN (remaining, fss->frame_size - fse->pcm_offset);
start = fse->pcm_offset * channels;
end = (len + fse->pcm_offset) * channels;
for (j = start; j < end; j++) {
fss->ipcm[j] = *p++ * (float)32767.0;
}
fse->pcm_offset += len;
if (fse->pcm_offset == fss->frame_size) {
nencoded += fs_speex_encode_block (fsound);
}
remaining -= len;
}
return frames - remaining;
}
static long
fs_speex_encode_f (FishSound * fsound, float * pcm[], long frames)
{
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
FishSoundSpeexEnc * fse = (FishSoundSpeexEnc *)fss->enc;
long remaining = frames, len, n = 0, nencoded = 0;
int j, start;
if (fss->packetno == 0)
fs_speex_enc_headers (fsound);
while (remaining > 0) {
len = MIN (remaining, fss->frame_size - fse->pcm_offset);
start = fse->pcm_offset;
fss->pcm[0] = &pcm[0][n];
if (fsound->info.channels == 2) {
fss->pcm[1] = &pcm[1][n];
_fs_interleave (fss->pcm, (float **)&fss->ipcm[start*2],
len, 2, 32767.0);
} else {
for (j = 0; j < len; j++) {
fss->ipcm[start + j] = fss->pcm[0][j] * (float)32767.0;
}
}
fse->pcm_offset += len;
if (fse->pcm_offset == fss->frame_size) {
nencoded += fs_speex_encode_block (fsound);
}
remaining -= len;
n += len;
}
return frames - remaining;
}
static long
fs_speex_flush (FishSound * fsound)
{
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
FishSoundSpeexEnc * fse = (FishSoundSpeexEnc *)fss->enc;
long nencoded = 0;
if (fsound->mode != FISH_SOUND_ENCODE)
return 0;
if (fse->pcm_offset > 0) {
nencoded += fs_speex_encode_block (fsound);
}
/* If, at this point, fse->frame_offset == 0, then either:
- all remaining encoded data has just been flushed out via
fs_speex_encode_block(), OR
- there was no data remaining to flush at the beginning of this
function (fse->pcm_offset == 0 && fse->frame_offset == 0)
*/
if (fse->frame_offset == 0) return 0;
while (fse->frame_offset < fss->nframes) {
speex_bits_pack (&fss->bits, 15, 5);
fse->frame_offset++;
}
nencoded += fs_speex_encode_write (fsound);
fse->frame_offset = 0;
return nencoded;
}
#else /* !FS_ENCODE */
#define fs_speex_encode_f NULL
#define fs_speex_encode_f_ilv NULL
#define fs_speex_flush NULL
#endif
static int
fs_speex_reset (FishSound * fsound)
{
/*FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;*/
return 0;
}
static int
fs_speex_update (FishSound * fsound, int interleave)
{
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
size_t pcm_size = sizeof (float);
fss->ipcm = (float *)
fs_realloc (fss->ipcm,
pcm_size * fss->frame_size * fsound->info.channels);
if (interleave) {
/* if transitioning from non-interleave to interleave,
free non-ilv buffers */
if (!fsound->interleave && fsound->info.channels == 2) {
if (fss->pcm[0]) fs_free (fss->pcm[0]);
if (fss->pcm[1]) fs_free (fss->pcm[1]);
fss->pcm[0] = NULL;
fss->pcm[1] = NULL;
}
} else {
if (fsound->info.channels == 1) {
fss->pcm[0] = (float *) fss->ipcm;
} else if (fsound->info.channels == 2) {
fss->pcm[0] = fs_realloc (fss->pcm[0], pcm_size * fss->frame_size);
fss->pcm[1] = fs_realloc (fss->pcm[1], pcm_size * fss->frame_size);
}
}
return 0;
}
static FishSound *
fs_speex_enc_init (FishSound * fsound)
{
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
FishSoundSpeexEnc * fse;
fse = fs_malloc (sizeof (FishSoundSpeexEnc));
if (fse == NULL) return NULL;
fse->frame_offset = 0;
fse->pcm_offset = 0;
fse->id = 0;
fss->enc = fse;
return fsound;
}
static FishSound *
fs_speex_init (FishSound * fsound)
{
FishSoundSpeexInfo * fss;
SpeexStereoState stereo_init = SPEEX_STEREO_STATE_INIT;
fss = fs_malloc (sizeof (FishSoundSpeexInfo));
if (fss == NULL) return NULL;
fss->packetno = 0;
fss->st = NULL;
fss->frame_size = 0;
fss->nframes = 1;
fss->pcm_len = 0;
fss->ipcm = NULL;
fss->pcm[0] = NULL;
fss->pcm[1] = NULL;
memcpy (&fss->stereo, &stereo_init, sizeof (SpeexStereoState));
speex_bits_init (&fss->bits);
fsound->codec_data = fss;
if (fsound->mode == FISH_SOUND_ENCODE)
fs_speex_enc_init (fsound);
return fsound;
}
static FishSound *
fs_speex_delete (FishSound * fsound)
{
FishSoundSpeexInfo * fss = (FishSoundSpeexInfo *)fsound->codec_data;
fs_speex_free_buffers (fsound);
if (fsound->mode == FISH_SOUND_DECODE) {
if (fss->st) speex_decoder_destroy (fss->st);
} else if (fsound->mode == FISH_SOUND_ENCODE) {
if (fss->st) speex_encoder_destroy (fss->st);
if (fss->enc) fs_free (fss->enc);
}
speex_bits_destroy (&fss->bits);
fs_free (fss);
fsound->codec_data = NULL;
return fsound;
}
FishSoundCodec *
fish_sound_speex_codec (void)
{
FishSoundCodec * codec;
codec = (FishSoundCodec *) fs_malloc (sizeof (FishSoundCodec));
codec->format.format = FISH_SOUND_SPEEX;
codec->format.name = "Speex (Xiph.Org)";
codec->format.extension = "spx";
codec->init = fs_speex_init;
codec->del = fs_speex_delete;
codec->reset = fs_speex_reset;
codec->update = fs_speex_update;
codec->command = fs_speex_command;
codec->decode = fs_speex_decode;
codec->encode_f = fs_speex_encode_f;
codec->encode_f_ilv = fs_speex_encode_f_ilv;
codec->flush = fs_speex_flush;
return codec;
}
#else /* !HAVE_SPEEX */
int
fish_sound_speex_identify (unsigned char * buf, long bytes)
{
return FISH_SOUND_UNKNOWN;
}
FishSoundCodec *
fish_sound_speex_codec (void)
{
return NULL;
}
#endif

View File

@ -0,0 +1,508 @@
/*
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Organisation (CSIRO) Australia
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 name of CSIRO Australia nor the names of its
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 ORGANISATION 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.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "private.h"
#include "convert.h"
/*#define DEBUG*/
#if HAVE_VORBIS
#include <vorbis/codec.h>
#if HAVE_VORBISENC
#include <vorbis/vorbisenc.h>
#endif
typedef struct _FishSoundVorbisInfo {
int packetno;
int finished;
vorbis_info vi;
vorbis_comment vc;
vorbis_dsp_state vd; /** central working state for the PCM->packet encoder */
vorbis_block vb; /** local working space for PCM->packet encode */
float ** pcm; /** ongoing pcm working space for decoder (stateful) */
float * ipcm; /** interleaved pcm for interfacing with user */
long max_pcm;
} FishSoundVorbisInfo;
int
fish_sound_vorbis_identify (unsigned char * buf, long bytes)
{
struct vorbis_info vi;
struct vorbis_comment vc;
ogg_packet op;
int ret, id = FISH_SOUND_UNKNOWN;
if (!strncmp ((char *)&buf[1], "vorbis", 6)) {
/* if only a short buffer was passed, do a weak identify */
if (bytes == 8) return FISH_SOUND_VORBIS;
/* otherwise, assume the buffer is an entire initial header and
* feed it to vorbis_synthesis_headerin() */
vorbis_info_init (&vi);
vorbis_comment_init (&vc);
op.packet = buf;
op.bytes = bytes;
op.b_o_s = 1;
op.e_o_s = 0;
op.granulepos = 0;
op.packetno = 0;
if ((ret = vorbis_synthesis_headerin (&vi, &vc, &op)) == 0) {
if (vi.rate != 0) id = FISH_SOUND_VORBIS;
#ifdef DEBUG
} else {
printf ("vorbis_synthesis_headerin returned %d\n", ret);
#endif
}
vorbis_info_clear (&vi);
}
return id;
}
static int
fs_vorbis_command (FishSound * fsound, int command, void * data,
int datasize)
{
return 0;
}
#if FS_DECODE
static long
fs_vorbis_decode (FishSound * fsound, unsigned char * buf, long bytes)
{
FishSoundVorbisInfo * fsv = (FishSoundVorbisInfo *)fsound->codec_data;
ogg_packet op;
long samples;
int ret;
/* Make an ogg_packet structure to pass the data to libvorbis */
op.packet = buf;
op.bytes = bytes;
op.b_o_s = (fsv->packetno == 0) ? 1 : 0;
op.e_o_s = fsound->next_eos;
op.granulepos = fsound->next_granulepos;
op.packetno = fsv->packetno;
if (fsv->packetno < 3) {
if ((ret = vorbis_synthesis_headerin (&fsv->vi, &fsv->vc, &op)) == 0) {
if (fsv->vi.rate != 0) {
#ifdef DEBUG
printf ("Got vorbis info: version %d\tchannels %d\trate %ld\n",
fsv->vi.version, fsv->vi.channels, fsv->vi.rate);
#endif
fsound->info.samplerate = fsv->vi.rate;
fsound->info.channels = fsv->vi.channels;
}
}
/* Decode comments from packet 1. Vorbis has 7 bytes of marker at the
* start of vorbiscomment packet. */
if (fsv->packetno == 1 && bytes > 7 && buf[0] == 0x03 &&
!strncmp ((char *)&buf[1], "vorbis", 6)) {
fish_sound_comments_decode (fsound, buf+7, bytes-7);
} else if (fsv->packetno == 2) {
vorbis_synthesis_init (&fsv->vd, &fsv->vi);
vorbis_block_init (&fsv->vd, &fsv->vb);
}
} else {
FishSoundDecoded_FloatIlv df;
FishSoundDecoded_Float dfi;
if (vorbis_synthesis (&fsv->vb, &op) == 0)
vorbis_synthesis_blockin (&fsv->vd, &fsv->vb);
while ((samples = vorbis_synthesis_pcmout (&fsv->vd, &fsv->pcm)) > 0) {
vorbis_synthesis_read (&fsv->vd, samples);
if (fsound->frameno != -1)
fsound->frameno += samples;
if (fsound->interleave) {
if (samples > fsv->max_pcm) {
fsv->ipcm = realloc (fsv->ipcm, sizeof(float) * samples *
fsound->info.channels);
fsv->max_pcm = samples;
}
_fs_interleave (fsv->pcm, (float **)fsv->ipcm, samples,
fsound->info.channels, 1.0);
dfi = (FishSoundDecoded_FloatIlv)fsound->callback.decoded_float_ilv;
dfi (fsound, (float **)fsv->ipcm, samples, fsound->user_data);
} else {
df = (FishSoundDecoded_Float)fsound->callback.decoded_float;
df (fsound, fsv->pcm, samples, fsound->user_data);
}
}
}
if (fsound->next_granulepos != -1) {
fsound->frameno = fsound->next_granulepos;
fsound->next_granulepos = -1;
}
fsv->packetno++;
return 0;
}
#else /* !FS_DECODE */
#define fs_vorbis_decode NULL
#endif
#if FS_ENCODE && HAVE_VORBISENC
static FishSound *
fs_vorbis_enc_headers (FishSound * fsound)
{
FishSoundVorbisInfo * fsv = (FishSoundVorbisInfo *)fsound->codec_data;
const FishSoundComment * comment;
ogg_packet header;
ogg_packet header_comm;
ogg_packet header_code;
/* Vorbis streams begin with three headers; the initial header (with
most of the codec setup parameters) which is mandated by the Ogg
bitstream spec. The second header holds any comment fields. The
third header holds the bitstream codebook. We merely need to
make the headers, then pass them to libvorbis one at a time;
libvorbis handles the additional Ogg bitstream constraints */
/* Update the comments */
for (comment = fish_sound_comment_first (fsound); comment;
comment = fish_sound_comment_next (fsound, comment)) {
#ifdef DEBUG
fprintf (stderr, "fs_vorbis_enc_headers: %s = %s\n",
comment->name, comment->value);
#endif
vorbis_comment_add_tag (&fsv->vc, comment->name, comment->value);
}
/* Generate the headers */
vorbis_analysis_headerout(&fsv->vd, &fsv->vc,
&header, &header_comm, &header_code);
/* Pass the generated headers to the user */
if (fsound->callback.encoded) {
FishSoundEncoded encoded = (FishSoundEncoded)fsound->callback.encoded;
encoded (fsound, header.packet, header.bytes, fsound->user_data);
encoded (fsound, header_comm.packet, header_comm.bytes,
fsound->user_data);
encoded (fsound, header_code.packet, header_code.bytes,
fsound->user_data);
fsv->packetno = 3;
}
return fsound;
}
static long
fs_vorbis_encode_write (FishSound * fsound, long len)
{
FishSoundVorbisInfo * fsv = (FishSoundVorbisInfo *)fsound->codec_data;
ogg_packet op;
vorbis_analysis_wrote (&fsv->vd, len);
while (vorbis_analysis_blockout (&fsv->vd, &fsv->vb) == 1) {
vorbis_analysis (&fsv->vb, NULL);
vorbis_bitrate_addblock (&fsv->vb);
while (vorbis_bitrate_flushpacket (&fsv->vd, &op)) {
if (fsound->callback.encoded) {
FishSoundEncoded encoded = (FishSoundEncoded)fsound->callback.encoded;
if (op.granulepos != -1)
fsound->frameno = op.granulepos;
encoded (fsound, op.packet, op.bytes, fsound->user_data);
fsv->packetno++;
}
}
}
return len;
}
static int
fs_vorbis_finish (FishSound * fsound)
{
FishSoundVorbisInfo * fsv = (FishSoundVorbisInfo *)fsound->codec_data;
if (!fsv->finished) {
if (fsound->mode == FISH_SOUND_ENCODE) {
fs_vorbis_encode_write (fsound, 0);
}
fsv->finished = 1;
}
return 0;
}
static long
fs_vorbis_encode_f_ilv (FishSound * fsound, float ** pcm, long frames)
{
FishSoundVorbisInfo * fsv = (FishSoundVorbisInfo *)fsound->codec_data;
float ** vpcm;
long len, remaining = frames;
float * d = (float *)pcm;
if (fsv->packetno == 0) {
fs_vorbis_enc_headers (fsound);
}
if (frames == 0) {
fs_vorbis_finish (fsound);
return 0;
}
while (remaining > 0) {
len = MIN (1024, remaining);
/* expose the buffer to submit data */
vpcm = vorbis_analysis_buffer (&fsv->vd, 1024);
_fs_deinterleave ((float **)d, vpcm, len, fsound->info.channels, 1.0);
d += (len * fsound->info.channels);
fs_vorbis_encode_write (fsound, len);
remaining -= len;
}
/**
* End of input. Tell libvorbis we're at the end of stream so that it can
* handle the last frame and mark the end of stream in the output properly.
*/
if (fsound->next_eos)
fs_vorbis_finish (fsound);
return 0;
}
static long
fs_vorbis_encode_f (FishSound * fsound, float * pcm[], long frames)
{
FishSoundVorbisInfo * fsv = (FishSoundVorbisInfo *)fsound->codec_data;
float ** vpcm;
long len, remaining = frames;
int i;
float ** ppcm = alloca (sizeof (float *) * fsound->info.channels);
if (fsv->packetno == 0) {
fs_vorbis_enc_headers (fsound);
}
if (frames == 0) {
fs_vorbis_finish (fsound);
return 0;
}
for (i = 0; i < fsound->info.channels; i++) {
ppcm[i] = pcm[i];
}
while (remaining > 0) {
len = MIN (1024, remaining);
#ifdef DEBUG
printf ("fs_vorbis_encode: processing %ld frames\n", len);
#endif
/* expose the buffer to submit data */
vpcm = vorbis_analysis_buffer (&fsv->vd, 1024);
for (i = 0; i < fsound->info.channels; i++) {
memcpy (vpcm[i], ppcm[i], sizeof (float) * len);
}
fs_vorbis_encode_write (fsound, len);
remaining -= len;
}
/**
* End of input. Tell libvorbis we're at the end of stream so that it can
* handle the last frame and mark the end of stream in the output properly.
*/
if (fsound->next_eos)
fs_vorbis_finish (fsound);
return 0;
}
static FishSound *
fs_vorbis_enc_init (FishSound * fsound)
{
FishSoundVorbisInfo * fsv = (FishSoundVorbisInfo *)fsound->codec_data;
#ifdef DEBUG
printf ("Vorbis enc init: %d channels, %d Hz\n", fsound->info.channels,
fsound->info.samplerate);
#endif
vorbis_encode_init_vbr (&fsv->vi, fsound->info.channels,
fsound->info.samplerate, (float)0.3 /* quality */);
/* set up the analysis state and auxiliary encoding storage */
vorbis_analysis_init (&fsv->vd, &fsv->vi);
vorbis_block_init (&fsv->vd, &fsv->vb);
return fsound;
}
#else /* ! FS_ENCODE && HAVE_VORBISENC */
#define fs_vorbis_encode_f NULL
#define fs_vorbis_encode_f_ilv NULL
#define fs_vorbis_finish NULL
#endif /* ! FS_ENCODE && HAVE_VORBISENC */
static int
fs_vorbis_reset (FishSound * fsound)
{
FishSoundVorbisInfo * fsv = (FishSoundVorbisInfo *)fsound->codec_data;
vorbis_block_init (&fsv->vd, &fsv->vb);
return 0;
}
static FishSound *
fs_vorbis_init (FishSound * fsound)
{
FishSoundVorbisInfo * fsv;
fsv = fs_malloc (sizeof (FishSoundVorbisInfo));
if (fsv == NULL) return NULL;
fsv->packetno = 0;
fsv->finished = 0;
vorbis_info_init (&fsv->vi);
vorbis_comment_init (&fsv->vc);
fsv->pcm = NULL;
fsv->ipcm = NULL;
fsv->max_pcm = 0;
fsound->codec_data = fsv;
#if FS_ENCODE && HAVE_VORBISENC
if (fsound->mode == FISH_SOUND_ENCODE) {
fs_vorbis_enc_init (fsound);
}
#endif /* FS_ENCODE && HAVE_VORBISENC */
return fsound;
}
static FishSound *
fs_vorbis_delete (FishSound * fsound)
{
FishSoundVorbisInfo * fsv = (FishSoundVorbisInfo *)fsound->codec_data;
#if FS_ENCODE && HAVE_VORBISENC
fs_vorbis_finish (fsound);
#endif /* FS_ENCODE && HAVE_VORBISENC */
if (fsv->ipcm) fs_free (fsv->ipcm);
vorbis_block_clear (&fsv->vb);
vorbis_dsp_clear (&fsv->vd);
vorbis_comment_clear (&fsv->vc);
vorbis_info_clear (&fsv->vi);
fs_free (fsv);
fsound->codec_data = NULL;
return fsound;
}
FishSoundCodec *
fish_sound_vorbis_codec (void)
{
FishSoundCodec * codec;
codec = (FishSoundCodec *) fs_malloc (sizeof (FishSoundCodec));
codec->format.format = FISH_SOUND_VORBIS;
codec->format.name = "Vorbis (Xiph.Org)";
codec->format.extension = "ogg";
codec->init = fs_vorbis_init;
codec->del = fs_vorbis_delete;
codec->reset = fs_vorbis_reset;
codec->update = NULL; /* XXX */
codec->command = fs_vorbis_command;
codec->decode = fs_vorbis_decode;
codec->encode_f = fs_vorbis_encode_f;
codec->encode_f_ilv = fs_vorbis_encode_f_ilv;
codec->flush = NULL;
return codec;
}
#else /* !HAVE_VORBIS */
int
fish_sound_vorbis_identify (unsigned char * buf, long bytes)
{
return FISH_SOUND_UNKNOWN;
}
FishSoundCodec *
fish_sound_vorbis_codec (void)
{
return NULL;
}
#endif

View File

@ -0,0 +1,57 @@
/*
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Organisation (CSIRO) Australia
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 name of CSIRO Australia nor the names of its
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 ORGANISATION 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.
*/
#include "config.h"
/* WINDOWS */
#ifdef _WIN32
#define inline __inline
#define alloca _alloca
#define strncasecmp _strnicmp
#define snprintf _snprintf
#ifndef __SYMBIAN32__
#define strcasecmp _stricmp
#endif /* ! __SYMBIAN32__ */
#endif
/* malloc/realloc/free macros */
#ifndef fs_malloc
#define fs_malloc malloc
#endif
#ifndef fs_realloc
#define fs_realloc realloc
#endif
#ifndef fs_free
#define fs_free free
#endif

View File

@ -0,0 +1,234 @@
/*
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Organisation (CSIRO) Australia
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 name of CSIRO Australia nor the names of its
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 ORGANISATION 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "fs_compat.h"
typedef int (*FishSoundFunc) (void * data);
typedef int (*FishSoundCmpFunc) (const void * data1, const void * data2);
typedef struct _FishSoundVector FishSoundVector;
struct _FishSoundVector {
int max_elements;
int nr_elements;
FishSoundCmpFunc cmp;
void ** data;
};
/*
* A vector of void *. New elements will be appended at the tail.
*/
FishSoundVector *
fs_vector_new (FishSoundCmpFunc cmp)
{
FishSoundVector * vector;
vector = fs_malloc (sizeof (FishSoundVector));
vector->max_elements = 0;
vector->nr_elements = 0;
vector->cmp = cmp;
vector->data = NULL;
return vector;
}
static void
fs_vector_clear (FishSoundVector * vector)
{
fs_free (vector->data);
vector->data = NULL;
vector->nr_elements = 0;
vector->max_elements = 0;
}
void
fs_vector_delete (FishSoundVector * vector)
{
fs_vector_clear (vector);
fs_free (vector);
}
int
fs_vector_size (FishSoundVector * vector)
{
if (vector == NULL) return 0;
return vector->nr_elements;
}
void *
fs_vector_nth (FishSoundVector * vector, int n)
{
if (vector == NULL) return NULL;
if (n >= vector->nr_elements) return NULL;
return vector->data[n];
}
int
fs_vector_find_index (FishSoundVector * vector, const void * data)
{
void * v_data;
int i;
for (i = 0; i < vector->nr_elements; i++) {
v_data = vector->data[i];
if (vector->cmp (v_data, data))
return i;
}
return -1;
}
void *
fs_vector_find (FishSoundVector * vector, const void * data)
{
void * v_data;
int i;
for (i = 0; i < vector->nr_elements; i++) {
v_data = vector->data[i];
if (vector->cmp (v_data, data))
return v_data;
}
return NULL;
}
int
fs_vector_foreach (FishSoundVector * vector, FishSoundFunc func)
{
int i;
for (i = 0; i < vector->nr_elements; i++) {
func (vector->data[i]);
}
return 0;
}
static FishSoundVector *
fs_vector_grow (FishSoundVector * vector)
{
void * new_elements;
int new_max_elements;
vector->nr_elements++;
if (vector->nr_elements > vector->max_elements) {
if (vector->max_elements == 0) {
new_max_elements = 1;
} else {
new_max_elements = vector->max_elements * 2;
}
new_elements =
fs_realloc (vector->data, (size_t)new_max_elements * sizeof (void *));
if (new_elements == NULL) {
vector->nr_elements--;
return NULL;
}
vector->max_elements = new_max_elements;
vector->data = new_elements;
}
return vector;
}
void *
fs_vector_insert (FishSoundVector * vector, void * data)
{
if (fs_vector_grow (vector) == NULL)
return NULL;
vector->data[vector->nr_elements-1] = data;
return data;
}
static void *
fs_vector_remove_nth (FishSoundVector * vector, int n)
{
int i;
void * new_elements;
int new_max_elements;
vector->nr_elements--;
if (vector->nr_elements == 0) {
fs_vector_clear (vector);
} else {
for (i = n; i < vector->nr_elements; i++) {
vector->data[i] = vector->data[i+1];
}
if (vector->nr_elements < vector->max_elements/2) {
new_max_elements = vector->max_elements/2;
new_elements =
fs_realloc (vector->data,
(size_t)new_max_elements * sizeof (void *));
if (new_elements == NULL)
return NULL;
vector->max_elements = new_max_elements;
vector->data = new_elements;
}
}
return vector;
}
FishSoundVector *
fs_vector_remove (FishSoundVector * vector, void * data)
{
int i;
for (i = 0; i < vector->nr_elements; i++) {
if (vector->data[i] == data) {
return fs_vector_remove_nth (vector, i);
}
}
return vector;
}

View File

@ -0,0 +1,80 @@
/*
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Organisation (CSIRO) Australia
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 name of CSIRO Australia nor the names of its
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 ORGANISATION 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.
*/
#ifndef __FS_VECTOR_H__
#define __FS_VECTOR_H__
typedef void FishSoundVector;
typedef int (*FishSoundFunc) (void * data);
typedef int (*FishSoundCmpFunc) (void * data1, void * data2);
FishSoundVector *
fs_vector_new (FishSoundCmpFunc cmp);
void
fs_vector_delete (FishSoundVector * vector);
void *
fs_vector_nth (FishSoundVector * vector, int n);
int
fs_vector_find_index (FishSoundVector * vector, const void * data);
void *
fs_vector_find (FishSoundVector * vector, const void * data);
int
fs_vector_foreach (FishSoundVector * vector, FishSoundFunc func);
int
fs_vector_size (FishSoundVector * vector);
/**
* Add an element to a vector.
* \param vector An FishSoundVector
* \param data The new element to add
* \retval data If the element was successfully added
* \retval NULL If adding the element failed due to a realloc() error
*/
void *
fs_vector_insert (FishSoundVector * vector, void * data);
/**
* Remove a (void *) element of a vector
* \retval \a vector on success
* \retval NULL on failure (realloc error)
*/
FishSoundVector *
fs_vector_remove (FishSoundVector * vector, void * data);
#endif /* __FS_VECTOR_H__ */

View File

@ -0,0 +1,189 @@
/*
Copyright (C) 2003 Commonwealth Scientific and Industrial Research
Organisation (CSIRO) Australia
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 name of CSIRO Australia nor the names of its
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 ORGANISATION 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.
*/
#ifndef __FISH_SOUND_PRIVATE_H__
#define __FISH_SOUND_PRIVATE_H__
#include <stdlib.h>
#include "fs_compat.h"
#include "fs_vector.h"
#include <fishsound/constants.h>
#undef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
typedef struct _FishSound FishSound;
typedef struct _FishSoundInfo FishSoundInfo;
typedef struct _FishSoundCodec FishSoundCodec;
typedef struct _FishSoundFormat FishSoundFormat;
typedef struct _FishSoundComment FishSoundComment;
typedef int (*FSCodecIdentify) (unsigned char * buf, long bytes);
typedef FishSound * (*FSCodecInit) (FishSound * fsound);
typedef FishSound * (*FSCodecDelete) (FishSound * fsound);
typedef int (*FSCodecReset) (FishSound * fsound);
typedef int (*FSCodecUpdate) (FishSound * fsound, int interleave);
typedef int (*FSCodecCommand) (FishSound * fsound, int command,
void * data, int datasize);
typedef long (*FSCodecDecode) (FishSound * fsound, unsigned char * buf,
long bytes);
typedef long (*FSCodecEncode_Float) (FishSound * fsound, float * pcm[],
long frames);
typedef long (*FSCodecEncode_FloatIlv) (FishSound * fsound,
float ** pcm, long frames);
typedef long (*FSCodecFlush) (FishSound * fsound);
#include <fishsound/decode.h>
#include <fishsound/encode.h>
struct _FishSoundFormat {
int format;
const char * name;
const char * extension;
};
struct _FishSoundCodec {
struct _FishSoundFormat format;
FSCodecInit init;
FSCodecDelete del;
FSCodecReset reset;
FSCodecUpdate update;
FSCodecCommand command;
FSCodecDecode decode;
FSCodecEncode_FloatIlv encode_f_ilv;
FSCodecEncode_Float encode_f;
FSCodecFlush flush;
};
struct _FishSoundInfo {
int samplerate;
int channels;
int format;
};
struct _FishSoundComment {
char * name;
char * value;
};
union FishSoundCallback {
FishSoundDecoded_Float decoded_float;
FishSoundDecoded_FloatIlv decoded_float_ilv;
FishSoundEncoded encoded;
};
struct _FishSound {
/** FISH_SOUND_DECODE or FISH_SOUND_ENCODE */
FishSoundMode mode;
/** General info related to sound */
FishSoundInfo info;
/** Interleave boolean */
int interleave;
/**
* Current frameno.
*/
long frameno;
/**
* Truncation frameno for the next block of data sent to decode.
* In Ogg encapsulation, this is represented by the Ogg packet's
* "granulepos" field.
*/
long next_granulepos;
/**
* Flag if the next block of data sent to decode will be the last one
* for this stream (eos = End Of Stream).
* In Ogg encapsulation, this is represented by the Ogg packet's
* "eos" field.
*/
int next_eos;
/** The codec class structure */
FishSoundCodec * codec;
/** codec specific data */
void * codec_data;
/* encode or decode callback */
union FishSoundCallback callback;
/** user data for encode/decode callback */
void * user_data;
/** The comments */
char * vendor;
FishSoundVector * comments;
};
int fish_sound_identify (unsigned char * buf, long bytes);
int fish_sound_set_format (FishSound * fsound, int format);
/* Format specific interfaces */
int fish_sound_vorbis_identify (unsigned char * buf, long bytes);
FishSoundCodec * fish_sound_vorbis_codec (void);
int fish_sound_speex_identify (unsigned char * buf, long bytes);
FishSoundCodec * fish_sound_speex_codec (void);
int fish_sound_flac_identify (unsigned char * buf, long bytes);
FishSoundCodec * fish_sound_flac_codec (void);
/* comments */
int fish_sound_comments_init (FishSound * fsound);
int fish_sound_comments_free (FishSound * fsound);
int fish_sound_comments_decode (FishSound * fsound, unsigned char * buf,
long bytes);
long fish_sound_comments_encode (FishSound * fsound, unsigned char * buf,
long length);
/**
* Set the vendor string.
* \param fsound A FishSound* handle (created with FISH_SOUND_ENCODE)
* \param vendor The vendor string.
* \retval 0 Success
* \retval FISH_SOUND_ERR_BAD \a fsound is not a valid FishSound* handle
* \retval FISH_SOUND_ERR_INVALID Operation not suitable for this FishSound
*/
int
fish_sound_comment_set_vendor (FishSound * fsound, const char * vendor);
const FishSoundComment * fish_sound_comment_first (FishSound * fsound);
const FishSoundComment *
fish_sound_comment_next (FishSound * fsound, const FishSoundComment * comment);
#endif /* __FISH_SOUND_PRIVATE_H__ */

View File

@ -0,0 +1,40 @@
# Usage: cp $1/update.sh <libfishsound_src_directory>
#
# Copies the needed files from a directory containing the original
# libfishsound source that we need for the Mozilla HTML5 media support.
cp $1/config.h ./include/fishsound/config.h
echo "#undef FS_ENCODE" >>./include/fishsound/config.h
echo "#define FS_ENCODE 0" >>./include/fishsound/config.h
echo "#undef HAVE_FLAC" >>./include/fishsound/config.h
echo "#define HAVE_FLAC 0" >>./include/fishsound/config.h
echo "#undef HAVE_OGGZ" >>./include/fishsound/config.h
echo "#define HAVE_OGGZ 1" >>./include/fishsound/config.h
echo "#undef HAVE_SPEEX" >>./include/fishsound/config.h
echo "#define HAVE_SPEEX 0" >>./include/fishsound/config.h
echo "#undef HAVE_VORBIS" >>./include/fishsound/config.h
echo "#define HAVE_VORBIS 1" >>./include/fishsound/config.h
echo "#undef HAVE_VORBISENC" >>./include/fishsound/config.h
echo "#define HAVE_VORBISENC 0" >>./include/fishsound/config.h
echo "#undef DEBUG" >>./include/fishsound/config.h
cp $1/include/fishsound/encode.h ./include/fishsound/encode.h
cp $1/include/fishsound/comments.h ./include/fishsound/comments.h
cp $1/include/fishsound/deprecated.h ./include/fishsound/deprecated.h
cp $1/include/fishsound/fishsound.h ./include/fishsound/fishsound.h
cp $1/include/fishsound/constants.h ./include/fishsound/constants.h
cp $1/include/fishsound/decode.h ./include/fishsound/decode.h
cp $1/COPYING ./COPYING
cp $1/README ./README
cp ./include/fishsound/config.h ./src/libfishsound/config.h
cp $1/src/libfishsound/decode.c ./src/libfishsound/fishsound_decode.c
cp $1/src/libfishsound/fishsound.c ./src/libfishsound/fishsound.c
sed s/\#include\ \<vorbis\\/vorbisenc.h\>/\#if\ HAVE_VORBISENC\\n\#include\ \<vorbis\\/vorbisenc.h\>\\n\#endif/g $1/src/libfishsound/vorbis.c >./src/libfishsound/fishsound_vorbis.c
cp $1/src/libfishsound/flac.c ./src/libfishsound/fishsound_flac.c
cp $1/src/libfishsound/comments.c ./src/libfishsound/fishsound_comments.c
cp $1/src/libfishsound/private.h ./src/libfishsound/private.h
cp $1/src/libfishsound/fs_compat.h ./src/libfishsound/fs_compat.h
cp $1/src/libfishsound/speex.c ./src/libfishsound/fishsound_speex.c
cp $1/src/libfishsound/encode.c ./src/libfishsound/fishsound_encode.c
cp $1/src/libfishsound/fs_vector.h ./src/libfishsound/fs_vector.h
cp $1/src/libfishsound/fs_vector.c ./src/libfishsound/fs_vector.c
cp $1/src/libfishsound/convert.h ./src/libfishsound/convert.h
cp $1/AUTHORS ./AUTHORS