| @@ -0,0 +1,49 @@ | |||||
| ===================================================================== | |||||
| I've incorporated FLAC directly into the Juce codebase because it makes | |||||
| things much easier than having to make all your builds link correctly to | |||||
| the appropriate libraries on every different platform. | |||||
| I've made minimal changes to the FLAC code - just tweaked a few include paths | |||||
| to make it build smoothly, added some headers to allow you to turn off FLAC | |||||
| compilation, and commented-out a couple of unused bits of code. | |||||
| ===================================================================== | |||||
| The following license is the BSD-style license that comes with the | |||||
| Flac distribution, and which applies just to the files I've | |||||
| included in this directory. For more info, and to get the rest of the | |||||
| distribution, visit the Flac homepage: flac.sourceforge.net | |||||
| ===================================================================== | |||||
| Copyright (C) 2000,2001,2002,2003,2004,2005,2006 Josh Coalson | |||||
| 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 Xiph.org Foundation 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 FOUNDATION 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. | |||||
| @@ -0,0 +1,402 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__ALL_H | |||||
| #define FLAC__ALL_H | |||||
| #include "export.h" | |||||
| #include "assert.h" | |||||
| #include "callback.h" | |||||
| #include "format.h" | |||||
| #include "metadata.h" | |||||
| #include "ordinals.h" | |||||
| #include "stream_decoder.h" | |||||
| #include "stream_encoder.h" | |||||
| #ifdef _MSC_VER | |||||
| /* OPT: an MSVC built-in would be better */ | |||||
| static _inline FLAC__uint32 local_swap32_(FLAC__uint32 x) | |||||
| { | |||||
| x = ((x<<8)&0xFF00FF00) | ((x>>8)&0x00FF00FF); | |||||
| return (x>>16) | (x<<16); | |||||
| } | |||||
| #endif | |||||
| #if defined(_MSC_VER) && defined(_X86_) | |||||
| /* OPT: an MSVC built-in would be better */ | |||||
| static void local_swap32_block_(FLAC__uint32 *start, FLAC__uint32 len) | |||||
| { | |||||
| __asm { | |||||
| mov edx, start | |||||
| mov ecx, len | |||||
| test ecx, ecx | |||||
| loop1: | |||||
| jz done1 | |||||
| mov eax, [edx] | |||||
| bswap eax | |||||
| mov [edx], eax | |||||
| add edx, 4 | |||||
| dec ecx | |||||
| jmp short loop1 | |||||
| done1: | |||||
| } | |||||
| } | |||||
| #endif | |||||
| /** \mainpage | |||||
| * | |||||
| * \section intro Introduction | |||||
| * | |||||
| * This is the documentation for the FLAC C and C++ APIs. It is | |||||
| * highly interconnected; this introduction should give you a top | |||||
| * level idea of the structure and how to find the information you | |||||
| * need. As a prerequisite you should have at least a basic | |||||
| * knowledge of the FLAC format, documented | |||||
| * <A HREF="../format.html">here</A>. | |||||
| * | |||||
| * \section c_api FLAC C API | |||||
| * | |||||
| * The FLAC C API is the interface to libFLAC, a set of structures | |||||
| * describing the components of FLAC streams, and functions for | |||||
| * encoding and decoding streams, as well as manipulating FLAC | |||||
| * metadata in files. The public include files will be installed | |||||
| * in your include area (for example /usr/include/FLAC/...). | |||||
| * | |||||
| * By writing a little code and linking against libFLAC, it is | |||||
| * relatively easy to add FLAC support to another program. The | |||||
| * library is licensed under <A HREF="../license.html">Xiph's BSD license</A>. | |||||
| * Complete source code of libFLAC as well as the command-line | |||||
| * encoder and plugins is available and is a useful source of | |||||
| * examples. | |||||
| * | |||||
| * Aside from encoders and decoders, libFLAC provides a powerful | |||||
| * metadata interface for manipulating metadata in FLAC files. It | |||||
| * allows the user to add, delete, and modify FLAC metadata blocks | |||||
| * and it can automatically take advantage of PADDING blocks to avoid | |||||
| * rewriting the entire FLAC file when changing the size of the | |||||
| * metadata. | |||||
| * | |||||
| * libFLAC usually only requires the standard C library and C math | |||||
| * library. In particular, threading is not used so there is no | |||||
| * dependency on a thread library. However, libFLAC does not use | |||||
| * global variables and should be thread-safe. | |||||
| * | |||||
| * libFLAC also supports encoding to and decoding from Ogg FLAC. | |||||
| * However the metadata editing interfaces currently have limited | |||||
| * read-only support for Ogg FLAC files. | |||||
| * | |||||
| * \section cpp_api FLAC C++ API | |||||
| * | |||||
| * The FLAC C++ API is a set of classes that encapsulate the | |||||
| * structures and functions in libFLAC. They provide slightly more | |||||
| * functionality with respect to metadata but are otherwise | |||||
| * equivalent. For the most part, they share the same usage as | |||||
| * their counterparts in libFLAC, and the FLAC C API documentation | |||||
| * can be used as a supplement. The public include files | |||||
| * for the C++ API will be installed in your include area (for | |||||
| * example /usr/include/FLAC++/...). | |||||
| * | |||||
| * libFLAC++ is also licensed under | |||||
| * <A HREF="../license.html">Xiph's BSD license</A>. | |||||
| * | |||||
| * \section getting_started Getting Started | |||||
| * | |||||
| * A good starting point for learning the API is to browse through | |||||
| * the <A HREF="modules.html">modules</A>. Modules are logical | |||||
| * groupings of related functions or classes, which correspond roughly | |||||
| * to header files or sections of header files. Each module includes a | |||||
| * detailed description of the general usage of its functions or | |||||
| * classes. | |||||
| * | |||||
| * From there you can go on to look at the documentation of | |||||
| * individual functions. You can see different views of the individual | |||||
| * functions through the links in top bar across this page. | |||||
| * | |||||
| * If you prefer a more hands-on approach, you can jump right to some | |||||
| * <A HREF="../documentation_example_code.html">example code</A>. | |||||
| * | |||||
| * \section porting_guide Porting Guide | |||||
| * | |||||
| * Starting with FLAC 1.1.3 a \link porting Porting Guide \endlink | |||||
| * has been introduced which gives detailed instructions on how to | |||||
| * port your code to newer versions of FLAC. | |||||
| * | |||||
| * \section embedded_developers Embedded Developers | |||||
| * | |||||
| * libFLAC has grown larger over time as more functionality has been | |||||
| * included, but much of it may be unnecessary for a particular embedded | |||||
| * implementation. Unused parts may be pruned by some simple editing of | |||||
| * src/libFLAC/Makefile.am. In general, the decoders, encoders, and | |||||
| * metadata interface are all independent from each other. | |||||
| * | |||||
| * It is easiest to just describe the dependencies: | |||||
| * | |||||
| * - All modules depend on the \link flac_format Format \endlink module. | |||||
| * - The decoders and encoders depend on the bitbuffer. | |||||
| * - The decoder is independent of the encoder. The encoder uses the | |||||
| * decoder because of the verify feature, but this can be removed if | |||||
| * not needed. | |||||
| * - Parts of the metadata interface require the stream decoder (but not | |||||
| * the encoder). | |||||
| * - Ogg support is selectable through the compile time macro | |||||
| * \c FLAC__HAS_OGG. | |||||
| * | |||||
| * For example, if your application only requires the stream decoder, no | |||||
| * encoder, and no metadata interface, you can remove the stream encoder | |||||
| * and the metadata interface, which will greatly reduce the size of the | |||||
| * library. | |||||
| * | |||||
| * Also, there are several places in the libFLAC code with comments marked | |||||
| * with "OPT:" where a #define can be changed to enable code that might be | |||||
| * faster on a specific platform. Experimenting with these can yield faster | |||||
| * binaries. | |||||
| */ | |||||
| /** \defgroup porting Porting Guide for New Versions | |||||
| * | |||||
| * This module describes differences in the library interfaces from | |||||
| * version to version. It assists in the porting of code that uses | |||||
| * the libraries to newer versions of FLAC. | |||||
| * | |||||
| * One simple facility for making porting easier that has been added | |||||
| * in FLAC 1.1.3 is a set of \c #defines in \c export.h of each | |||||
| * library's includes (e.g. \c include/FLAC/export.h). The | |||||
| * \c #defines mirror the libraries' | |||||
| * <A HREF="http://www.gnu.org/software/libtool/manual.html#Libtool-versioning">libtool version numbers</A>, | |||||
| * e.g. in libFLAC there are \c FLAC_API_VERSION_CURRENT, | |||||
| * \c FLAC_API_VERSION_REVISION, and \c FLAC_API_VERSION_AGE. | |||||
| * These can be used to support multiple versions of an API during the | |||||
| * transition phase, e.g. | |||||
| * | |||||
| * \code | |||||
| * #if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT <= 7 | |||||
| * legacy code | |||||
| * #else | |||||
| * new code | |||||
| * #endif | |||||
| * \endcode | |||||
| * | |||||
| * The the source will work for multiple versions and the legacy code can | |||||
| * easily be removed when the transition is complete. | |||||
| * | |||||
| * Another available symbol is FLAC_API_SUPPORTS_OGG_FLAC (defined in | |||||
| * include/FLAC/export.h), which can be used to determine whether or not | |||||
| * the library has been compiled with support for Ogg FLAC. This is | |||||
| * simpler than trying to call an Ogg init function and catching the | |||||
| * error. | |||||
| */ | |||||
| /** \defgroup porting_1_1_2_to_1_1_3 Porting from FLAC 1.1.2 to 1.1.3 | |||||
| * \ingroup porting | |||||
| * | |||||
| * \brief | |||||
| * This module describes porting from FLAC 1.1.2 to FLAC 1.1.3. | |||||
| * | |||||
| * The main change between the APIs in 1.1.2 and 1.1.3 is that they have | |||||
| * been simplified. First, libOggFLAC has been merged into libFLAC and | |||||
| * libOggFLAC++ has been merged into libFLAC++. Second, both the three | |||||
| * decoding layers and three encoding layers have been merged into a | |||||
| * single stream decoder and stream encoder. That is, the functionality | |||||
| * of FLAC__SeekableStreamDecoder and FLAC__FileDecoder has been merged | |||||
| * into FLAC__StreamDecoder, and FLAC__SeekableStreamEncoder and | |||||
| * FLAC__FileEncoder into FLAC__StreamEncoder. Only the | |||||
| * FLAC__StreamDecoder and FLAC__StreamEncoder remain. What this means | |||||
| * is there is now a single API that can be used to encode or decode | |||||
| * streams to/from native FLAC or Ogg FLAC and the single API can work | |||||
| * on both seekable and non-seekable streams. | |||||
| * | |||||
| * Instead of creating an encoder or decoder of a certain layer, now the | |||||
| * client will always create a FLAC__StreamEncoder or | |||||
| * FLAC__StreamDecoder. The old layers are now differentiated by the | |||||
| * initialization function. For example, for the decoder, | |||||
| * FLAC__stream_decoder_init() has been replaced by | |||||
| * FLAC__stream_decoder_init_stream(). This init function takes | |||||
| * callbacks for the I/O, and the seeking callbacks are optional. This | |||||
| * allows the client to use the same object for seekable and | |||||
| * non-seekable streams. For decoding a FLAC file directly, the client | |||||
| * can use FLAC__stream_decoder_init_file() and pass just a filename | |||||
| * and fewer callbacks; most of the other callbacks are supplied | |||||
| * internally. For situations where fopen()ing by filename is not | |||||
| * possible (e.g. Unicode filenames on Windows) the client can instead | |||||
| * open the file itself and supply the FILE* to | |||||
| * FLAC__stream_decoder_init_FILE(). The init functions now returns a | |||||
| * FLAC__StreamDecoderInitStatus instead of FLAC__StreamDecoderState. | |||||
| * Since the callbacks and client data are now passed to the init | |||||
| * function, the FLAC__stream_decoder_set_*_callback() functions and | |||||
| * FLAC__stream_decoder_set_client_data() are no longer needed. The | |||||
| * rest of the calls to the decoder are the same as before. | |||||
| * | |||||
| * There are counterpart init functions for Ogg FLAC, e.g. | |||||
| * FLAC__stream_decoder_init_ogg_stream(). All the rest of the calls | |||||
| * and callbacks are the same as for native FLAC. | |||||
| * | |||||
| * As an example, in FLAC 1.1.2 a seekable stream decoder would have | |||||
| * been set up like so: | |||||
| * | |||||
| * \code | |||||
| * FLAC__SeekableStreamDecoder *decoder = FLAC__seekable_stream_decoder_new(); | |||||
| * if(decoder == NULL) do_something; | |||||
| * FLAC__seekable_stream_decoder_set_md5_checking(decoder, true); | |||||
| * [... other settings ...] | |||||
| * FLAC__seekable_stream_decoder_set_read_callback(decoder, my_read_callback); | |||||
| * FLAC__seekable_stream_decoder_set_seek_callback(decoder, my_seek_callback); | |||||
| * FLAC__seekable_stream_decoder_set_tell_callback(decoder, my_tell_callback); | |||||
| * FLAC__seekable_stream_decoder_set_length_callback(decoder, my_length_callback); | |||||
| * FLAC__seekable_stream_decoder_set_eof_callback(decoder, my_eof_callback); | |||||
| * FLAC__seekable_stream_decoder_set_write_callback(decoder, my_write_callback); | |||||
| * FLAC__seekable_stream_decoder_set_metadata_callback(decoder, my_metadata_callback); | |||||
| * FLAC__seekable_stream_decoder_set_error_callback(decoder, my_error_callback); | |||||
| * FLAC__seekable_stream_decoder_set_client_data(decoder, my_client_data); | |||||
| * if(FLAC__seekable_stream_decoder_init(decoder) != FLAC__SEEKABLE_STREAM_DECODER_OK) do_something; | |||||
| * \endcode | |||||
| * | |||||
| * In FLAC 1.1.3 it is like this: | |||||
| * | |||||
| * \code | |||||
| * FLAC__StreamDecoder *decoder = FLAC__stream_decoder_new(); | |||||
| * if(decoder == NULL) do_something; | |||||
| * FLAC__stream_decoder_set_md5_checking(decoder, true); | |||||
| * [... other settings ...] | |||||
| * if(FLAC__stream_decoder_init_stream( | |||||
| * decoder, | |||||
| * my_read_callback, | |||||
| * my_seek_callback, // or NULL | |||||
| * my_tell_callback, // or NULL | |||||
| * my_length_callback, // or NULL | |||||
| * my_eof_callback, // or NULL | |||||
| * my_write_callback, | |||||
| * my_metadata_callback, // or NULL | |||||
| * my_error_callback, | |||||
| * my_client_data | |||||
| * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something; | |||||
| * \endcode | |||||
| * | |||||
| * or you could do; | |||||
| * | |||||
| * \code | |||||
| * [...] | |||||
| * FILE *file = fopen("somefile.flac","rb"); | |||||
| * if(file == NULL) do_somthing; | |||||
| * if(FLAC__stream_decoder_init_FILE( | |||||
| * decoder, | |||||
| * file, | |||||
| * my_write_callback, | |||||
| * my_metadata_callback, // or NULL | |||||
| * my_error_callback, | |||||
| * my_client_data | |||||
| * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something; | |||||
| * \endcode | |||||
| * | |||||
| * or just: | |||||
| * | |||||
| * \code | |||||
| * [...] | |||||
| * if(FLAC__stream_decoder_init_file( | |||||
| * decoder, | |||||
| * "somefile.flac", | |||||
| * my_write_callback, | |||||
| * my_metadata_callback, // or NULL | |||||
| * my_error_callback, | |||||
| * my_client_data | |||||
| * ) != FLAC__STREAM_DECODER_INIT_STATUS_OK) do_something; | |||||
| * \endcode | |||||
| * | |||||
| * Another small change to the decoder is in how it handles unparseable | |||||
| * streams. Before, when the decoder found an unparseable stream | |||||
| * (reserved for when the decoder encounters a stream from a future | |||||
| * encoder that it can't parse), it changed the state to | |||||
| * \c FLAC__STREAM_DECODER_UNPARSEABLE_STREAM. Now the decoder instead | |||||
| * drops sync and calls the error callback with a new error code | |||||
| * \c FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM. This is | |||||
| * more robust. If your error callback does not discriminate on the the | |||||
| * error state, your code does not need to be changed. | |||||
| * | |||||
| * The encoder now has a new setting: | |||||
| * FLAC__stream_encoder_set_apodization(). This is for setting the | |||||
| * method used to window the data before LPC analysis. You only need to | |||||
| * add a call to this function if the default is not suitable. There | |||||
| * are also two new convenience functions that may be useful: | |||||
| * FLAC__metadata_object_cuesheet_calculate_cddb_id() and | |||||
| * FLAC__metadata_get_cuesheet(). | |||||
| * | |||||
| * The \a bytes parameter to FLAC__StreamDecoderReadCallback, | |||||
| * FLAC__StreamEncoderReadCallback, and FLAC__StreamEncoderWriteCallback | |||||
| * is now \c size_t instead of \c unsigned. | |||||
| */ | |||||
| /** \defgroup porting_1_1_3_to_1_1_4 Porting from FLAC 1.1.3 to 1.1.4 | |||||
| * \ingroup porting | |||||
| * | |||||
| * \brief | |||||
| * This module describes porting from FLAC 1.1.3 to FLAC 1.1.4. | |||||
| * | |||||
| * There were no changes to any of the interfaces from 1.1.3 to 1.1.4. | |||||
| * There was a slight change in the implementation of | |||||
| * FLAC__stream_encoder_set_metadata(); the function now makes a copy | |||||
| * of the \a metadata array of pointers so the client no longer needs | |||||
| * to maintain it after the call. The objects themselves that are | |||||
| * pointed to by the array are still not copied though and must be | |||||
| * maintained until the call to FLAC__stream_encoder_finish(). | |||||
| */ | |||||
| /** \defgroup porting_1_1_4_to_1_2_0 Porting from FLAC 1.1.4 to 1.2.0 | |||||
| * \ingroup porting | |||||
| * | |||||
| * \brief | |||||
| * This module describes porting from FLAC 1.1.4 to FLAC 1.2.0. | |||||
| * | |||||
| * There were only very minor changes to the interfaces from 1.1.4 to 1.2.0. | |||||
| * In libFLAC, \c FLAC__format_sample_rate_is_subset() was added. | |||||
| * In libFLAC++, \c FLAC::Decoder::Stream::get_decode_position() was added. | |||||
| * | |||||
| * Finally, value of the constant \c FLAC__FRAME_HEADER_RESERVED_LEN | |||||
| * has changed to reflect the conversion of one of the reserved bits | |||||
| * into active use. It used to be \c 2 and now is \c 1. However the | |||||
| * FLAC frame header length has not changed, so to skip the proper | |||||
| * number of bits, use \c FLAC__FRAME_HEADER_RESERVED_LEN + | |||||
| * \c FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN | |||||
| */ | |||||
| /** \defgroup flac FLAC C API | |||||
| * | |||||
| * The FLAC C API is the interface to libFLAC, a set of structures | |||||
| * describing the components of FLAC streams, and functions for | |||||
| * encoding and decoding streams, as well as manipulating FLAC | |||||
| * metadata in files. | |||||
| * | |||||
| * You should start with the format components as all other modules | |||||
| * are dependent on it. | |||||
| */ | |||||
| #endif | |||||
| @@ -0,0 +1,212 @@ | |||||
| /* alloc - Convenience routines for safely allocating memory | |||||
| * Copyright (C) 2007 Josh Coalson | |||||
| * | |||||
| * This library is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public | |||||
| * License as published by the Free Software Foundation; either | |||||
| * version 2.1 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| * Lesser General Public License for more details. | |||||
| * | |||||
| * You should have received a copy of the GNU Lesser General Public | |||||
| * License along with this library; if not, write to the Free Software | |||||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||||
| */ | |||||
| #ifndef FLAC__SHARE__ALLOC_H | |||||
| #define FLAC__SHARE__ALLOC_H | |||||
| #if HAVE_CONFIG_H | |||||
| # include <config.h> | |||||
| #endif | |||||
| /* WATCHOUT: for c++ you may have to #define __STDC_LIMIT_MACROS 1 real early | |||||
| * before #including this file, otherwise SIZE_MAX might not be defined | |||||
| */ | |||||
| #include <limits.h> /* for SIZE_MAX */ | |||||
| #if !defined _MSC_VER && !defined __MINGW32__ && !defined __EMX__ | |||||
| #include <stdint.h> /* for SIZE_MAX in case limits.h didn't get it */ | |||||
| #endif | |||||
| #include <stdlib.h> /* for size_t, malloc(), etc */ | |||||
| #ifndef SIZE_MAX | |||||
| # ifndef SIZE_T_MAX | |||||
| # ifdef _MSC_VER | |||||
| # define SIZE_T_MAX UINT_MAX | |||||
| # else | |||||
| # error | |||||
| # endif | |||||
| # endif | |||||
| # define SIZE_MAX SIZE_T_MAX | |||||
| #endif | |||||
| #ifndef FLaC__INLINE | |||||
| #define FLaC__INLINE | |||||
| #endif | |||||
| /* avoid malloc()ing 0 bytes, see: | |||||
| * https://www.securecoding.cert.org/confluence/display/seccode/MEM04-A.+Do+not+make+assumptions+about+the+result+of+allocating+0+bytes?focusedCommentId=5407003 | |||||
| */ | |||||
| static FLaC__INLINE void *safe_malloc_(size_t size) | |||||
| { | |||||
| /* malloc(0) is undefined; FLAC src convention is to always allocate */ | |||||
| if(!size) | |||||
| size++; | |||||
| return malloc(size); | |||||
| } | |||||
| static FLaC__INLINE void *safe_calloc_(size_t nmemb, size_t size) | |||||
| { | |||||
| if(!nmemb || !size) | |||||
| return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ | |||||
| return calloc(nmemb, size); | |||||
| } | |||||
| /*@@@@ there's probably a better way to prevent overflows when allocating untrusted sums but this works for now */ | |||||
| static FLaC__INLINE void *safe_malloc_add_2op_(size_t size1, size_t size2) | |||||
| { | |||||
| size2 += size1; | |||||
| if(size2 < size1) | |||||
| return 0; | |||||
| return safe_malloc_(size2); | |||||
| } | |||||
| static FLaC__INLINE void *safe_malloc_add_3op_(size_t size1, size_t size2, size_t size3) | |||||
| { | |||||
| size2 += size1; | |||||
| if(size2 < size1) | |||||
| return 0; | |||||
| size3 += size2; | |||||
| if(size3 < size2) | |||||
| return 0; | |||||
| return safe_malloc_(size3); | |||||
| } | |||||
| static FLaC__INLINE void *safe_malloc_add_4op_(size_t size1, size_t size2, size_t size3, size_t size4) | |||||
| { | |||||
| size2 += size1; | |||||
| if(size2 < size1) | |||||
| return 0; | |||||
| size3 += size2; | |||||
| if(size3 < size2) | |||||
| return 0; | |||||
| size4 += size3; | |||||
| if(size4 < size3) | |||||
| return 0; | |||||
| return safe_malloc_(size4); | |||||
| } | |||||
| static FLaC__INLINE void *safe_malloc_mul_2op_(size_t size1, size_t size2) | |||||
| #if 0 | |||||
| needs support for cases where sizeof(size_t) != 4 | |||||
| { | |||||
| /* could be faster #ifdef'ing off SIZEOF_SIZE_T */ | |||||
| if(sizeof(size_t) == 4) { | |||||
| if ((double)size1 * (double)size2 < 4294967296.0) | |||||
| return malloc(size1*size2); | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| #else | |||||
| /* better? */ | |||||
| { | |||||
| if(!size1 || !size2) | |||||
| return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ | |||||
| if(size1 > SIZE_MAX / size2) | |||||
| return 0; | |||||
| return malloc(size1*size2); | |||||
| } | |||||
| #endif | |||||
| static FLaC__INLINE void *safe_malloc_mul_3op_(size_t size1, size_t size2, size_t size3) | |||||
| { | |||||
| if(!size1 || !size2 || !size3) | |||||
| return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ | |||||
| if(size1 > SIZE_MAX / size2) | |||||
| return 0; | |||||
| size1 *= size2; | |||||
| if(size1 > SIZE_MAX / size3) | |||||
| return 0; | |||||
| return malloc(size1*size3); | |||||
| } | |||||
| /* size1*size2 + size3 */ | |||||
| static FLaC__INLINE void *safe_malloc_mul2add_(size_t size1, size_t size2, size_t size3) | |||||
| { | |||||
| if(!size1 || !size2) | |||||
| return safe_malloc_(size3); | |||||
| if(size1 > SIZE_MAX / size2) | |||||
| return 0; | |||||
| return safe_malloc_add_2op_(size1*size2, size3); | |||||
| } | |||||
| /* size1 * (size2 + size3) */ | |||||
| static FLaC__INLINE void *safe_malloc_muladd2_(size_t size1, size_t size2, size_t size3) | |||||
| { | |||||
| if(!size1 || (!size2 && !size3)) | |||||
| return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ | |||||
| size2 += size3; | |||||
| if(size2 < size3) | |||||
| return 0; | |||||
| return safe_malloc_mul_2op_(size1, size2); | |||||
| } | |||||
| static FLaC__INLINE void *safe_realloc_add_2op_(void *ptr, size_t size1, size_t size2) | |||||
| { | |||||
| size2 += size1; | |||||
| if(size2 < size1) | |||||
| return 0; | |||||
| return realloc(ptr, size2); | |||||
| } | |||||
| static FLaC__INLINE void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3) | |||||
| { | |||||
| size2 += size1; | |||||
| if(size2 < size1) | |||||
| return 0; | |||||
| size3 += size2; | |||||
| if(size3 < size2) | |||||
| return 0; | |||||
| return realloc(ptr, size3); | |||||
| } | |||||
| static FLaC__INLINE void *safe_realloc_add_4op_(void *ptr, size_t size1, size_t size2, size_t size3, size_t size4) | |||||
| { | |||||
| size2 += size1; | |||||
| if(size2 < size1) | |||||
| return 0; | |||||
| size3 += size2; | |||||
| if(size3 < size2) | |||||
| return 0; | |||||
| size4 += size3; | |||||
| if(size4 < size3) | |||||
| return 0; | |||||
| return realloc(ptr, size4); | |||||
| } | |||||
| static FLaC__INLINE void *safe_realloc_mul_2op_(void *ptr, size_t size1, size_t size2) | |||||
| { | |||||
| if(!size1 || !size2) | |||||
| return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ | |||||
| if(size1 > SIZE_MAX / size2) | |||||
| return 0; | |||||
| return realloc(ptr, size1*size2); | |||||
| } | |||||
| /* size1 * (size2 + size3) */ | |||||
| static FLaC__INLINE void *safe_realloc_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3) | |||||
| { | |||||
| if(!size1 || (!size2 && !size3)) | |||||
| return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ | |||||
| size2 += size3; | |||||
| if(size2 < size3) | |||||
| return 0; | |||||
| return safe_realloc_mul_2op_(ptr, size1, size2); | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,45 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__ASSERT_H | |||||
| #define FLAC__ASSERT_H | |||||
| /* we need this since some compilers (like MSVC) leave assert()s on release code (and we don't want to use their ASSERT) */ | |||||
| #ifdef DEBUG | |||||
| #include <assert.h> | |||||
| #define FLAC__ASSERT(x) assert(x) | |||||
| #define FLAC__ASSERT_DECLARATION(x) x | |||||
| #else | |||||
| #define FLAC__ASSERT(x) | |||||
| #define FLAC__ASSERT_DECLARATION(x) | |||||
| #endif | |||||
| #endif | |||||
| @@ -0,0 +1,184 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__CALLBACK_H | |||||
| #define FLAC__CALLBACK_H | |||||
| #include "ordinals.h" | |||||
| #include <stdlib.h> /* for size_t */ | |||||
| /** \file include/FLAC/callback.h | |||||
| * | |||||
| * \brief | |||||
| * This module defines the structures for describing I/O callbacks | |||||
| * to the other FLAC interfaces. | |||||
| * | |||||
| * See the detailed documentation for callbacks in the | |||||
| * \link flac_callbacks callbacks \endlink module. | |||||
| */ | |||||
| /** \defgroup flac_callbacks FLAC/callback.h: I/O callback structures | |||||
| * \ingroup flac | |||||
| * | |||||
| * \brief | |||||
| * This module defines the structures for describing I/O callbacks | |||||
| * to the other FLAC interfaces. | |||||
| * | |||||
| * The purpose of the I/O callback functions is to create a common way | |||||
| * for the metadata interfaces to handle I/O. | |||||
| * | |||||
| * Originally the metadata interfaces required filenames as the way of | |||||
| * specifying FLAC files to operate on. This is problematic in some | |||||
| * environments so there is an additional option to specify a set of | |||||
| * callbacks for doing I/O on the FLAC file, instead of the filename. | |||||
| * | |||||
| * In addition to the callbacks, a FLAC__IOHandle type is defined as an | |||||
| * opaque structure for a data source. | |||||
| * | |||||
| * The callback function prototypes are similar (but not identical) to the | |||||
| * stdio functions fread, fwrite, fseek, ftell, feof, and fclose. If you use | |||||
| * stdio streams to implement the callbacks, you can pass fread, fwrite, and | |||||
| * fclose anywhere a FLAC__IOCallback_Read, FLAC__IOCallback_Write, or | |||||
| * FLAC__IOCallback_Close is required, and a FILE* anywhere a FLAC__IOHandle | |||||
| * is required. \warning You generally CANNOT directly use fseek or ftell | |||||
| * for FLAC__IOCallback_Seek or FLAC__IOCallback_Tell since on most systems | |||||
| * these use 32-bit offsets and FLAC requires 64-bit offsets to deal with | |||||
| * large files. You will have to find an equivalent function (e.g. ftello), | |||||
| * or write a wrapper. The same is true for feof() since this is usually | |||||
| * implemented as a macro, not as a function whose address can be taken. | |||||
| * | |||||
| * \{ | |||||
| */ | |||||
| #ifdef __cplusplus | |||||
| extern "C" { | |||||
| #endif | |||||
| /** This is the opaque handle type used by the callbacks. Typically | |||||
| * this is a \c FILE* or address of a file descriptor. | |||||
| */ | |||||
| typedef void* FLAC__IOHandle; | |||||
| /** Signature for the read callback. | |||||
| * The signature and semantics match POSIX fread() implementations | |||||
| * and can generally be used interchangeably. | |||||
| * | |||||
| * \param ptr The address of the read buffer. | |||||
| * \param size The size of the records to be read. | |||||
| * \param nmemb The number of records to be read. | |||||
| * \param handle The handle to the data source. | |||||
| * \retval size_t | |||||
| * The number of records read. | |||||
| */ | |||||
| typedef size_t (*FLAC__IOCallback_Read) (void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle); | |||||
| /** Signature for the write callback. | |||||
| * The signature and semantics match POSIX fwrite() implementations | |||||
| * and can generally be used interchangeably. | |||||
| * | |||||
| * \param ptr The address of the write buffer. | |||||
| * \param size The size of the records to be written. | |||||
| * \param nmemb The number of records to be written. | |||||
| * \param handle The handle to the data source. | |||||
| * \retval size_t | |||||
| * The number of records written. | |||||
| */ | |||||
| typedef size_t (*FLAC__IOCallback_Write) (const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle); | |||||
| /** Signature for the seek callback. | |||||
| * The signature and semantics mostly match POSIX fseek() WITH ONE IMPORTANT | |||||
| * EXCEPTION: the offset is a 64-bit type whereas fseek() is generally 'long' | |||||
| * and 32-bits wide. | |||||
| * | |||||
| * \param handle The handle to the data source. | |||||
| * \param offset The new position, relative to \a whence | |||||
| * \param whence \c SEEK_SET, \c SEEK_CUR, or \c SEEK_END | |||||
| * \retval int | |||||
| * \c 0 on success, \c -1 on error. | |||||
| */ | |||||
| typedef int (*FLAC__IOCallback_Seek) (FLAC__IOHandle handle, FLAC__int64 offset, int whence); | |||||
| /** Signature for the tell callback. | |||||
| * The signature and semantics mostly match POSIX ftell() WITH ONE IMPORTANT | |||||
| * EXCEPTION: the offset is a 64-bit type whereas ftell() is generally 'long' | |||||
| * and 32-bits wide. | |||||
| * | |||||
| * \param handle The handle to the data source. | |||||
| * \retval FLAC__int64 | |||||
| * The current position on success, \c -1 on error. | |||||
| */ | |||||
| typedef FLAC__int64 (*FLAC__IOCallback_Tell) (FLAC__IOHandle handle); | |||||
| /** Signature for the EOF callback. | |||||
| * The signature and semantics mostly match POSIX feof() but WATCHOUT: | |||||
| * on many systems, feof() is a macro, so in this case a wrapper function | |||||
| * must be provided instead. | |||||
| * | |||||
| * \param handle The handle to the data source. | |||||
| * \retval int | |||||
| * \c 0 if not at end of file, nonzero if at end of file. | |||||
| */ | |||||
| typedef int (*FLAC__IOCallback_Eof) (FLAC__IOHandle handle); | |||||
| /** Signature for the close callback. | |||||
| * The signature and semantics match POSIX fclose() implementations | |||||
| * and can generally be used interchangeably. | |||||
| * | |||||
| * \param handle The handle to the data source. | |||||
| * \retval int | |||||
| * \c 0 on success, \c EOF on error. | |||||
| */ | |||||
| typedef int (*FLAC__IOCallback_Close) (FLAC__IOHandle handle); | |||||
| /** A structure for holding a set of callbacks. | |||||
| * Each FLAC interface that requires a FLAC__IOCallbacks structure will | |||||
| * describe which of the callbacks are required. The ones that are not | |||||
| * required may be set to NULL. | |||||
| * | |||||
| * If the seek requirement for an interface is optional, you can signify that | |||||
| * a data sorce is not seekable by setting the \a seek field to \c NULL. | |||||
| */ | |||||
| typedef struct { | |||||
| FLAC__IOCallback_Read read; | |||||
| FLAC__IOCallback_Write write; | |||||
| FLAC__IOCallback_Seek seek; | |||||
| FLAC__IOCallback_Tell tell; | |||||
| FLAC__IOCallback_Eof eof; | |||||
| FLAC__IOCallback_Close close; | |||||
| } FLAC__IOCallbacks; | |||||
| /* \} */ | |||||
| #ifdef __cplusplus | |||||
| } | |||||
| #endif | |||||
| #endif | |||||
| @@ -0,0 +1,91 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__EXPORT_H | |||||
| #define FLAC__EXPORT_H | |||||
| /** \file include/FLAC/export.h | |||||
| * | |||||
| * \brief | |||||
| * This module contains #defines and symbols for exporting function | |||||
| * calls, and providing version information and compiled-in features. | |||||
| * | |||||
| * See the \link flac_export export \endlink module. | |||||
| */ | |||||
| /** \defgroup flac_export FLAC/export.h: export symbols | |||||
| * \ingroup flac | |||||
| * | |||||
| * \brief | |||||
| * This module contains #defines and symbols for exporting function | |||||
| * calls, and providing version information and compiled-in features. | |||||
| * | |||||
| * If you are compiling with MSVC and will link to the static library | |||||
| * (libFLAC.lib) you should define FLAC__NO_DLL in your project to | |||||
| * make sure the symbols are exported properly. | |||||
| * | |||||
| * \{ | |||||
| */ | |||||
| #if defined(FLAC__NO_DLL) || !defined(_MSC_VER) | |||||
| #define FLAC_API | |||||
| #else | |||||
| #ifdef FLAC_API_EXPORTS | |||||
| #define FLAC_API _declspec(dllexport) | |||||
| #else | |||||
| #define FLAC_API _declspec(dllimport) | |||||
| #endif | |||||
| #endif | |||||
| /** These #defines will mirror the libtool-based library version number, see | |||||
| * http://www.gnu.org/software/libtool/manual.html#Libtool-versioning | |||||
| */ | |||||
| #define FLAC_API_VERSION_CURRENT 10 | |||||
| #define FLAC_API_VERSION_REVISION 0 /**< see above */ | |||||
| #define FLAC_API_VERSION_AGE 2 /**< see above */ | |||||
| #ifdef __cplusplus | |||||
| extern "C" { | |||||
| #endif | |||||
| /** \c 1 if the library has been compiled with support for Ogg FLAC, else \c 0. */ | |||||
| extern FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC; | |||||
| #ifdef __cplusplus | |||||
| } | |||||
| #endif | |||||
| /* \} */ | |||||
| #endif | |||||
| @@ -0,0 +1,155 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 "juce_FlacHeader.h" | |||||
| #if JUCE_USE_FLAC | |||||
| #if HAVE_CONFIG_H | |||||
| # include <config.h> | |||||
| #endif | |||||
| #include "include/private/bitmath.h" | |||||
| #include "../assert.h" | |||||
| /* An example of what FLAC__bitmath_ilog2() computes: | |||||
| * | |||||
| * ilog2( 0) = assertion failure | |||||
| * ilog2( 1) = 0 | |||||
| * ilog2( 2) = 1 | |||||
| * ilog2( 3) = 1 | |||||
| * ilog2( 4) = 2 | |||||
| * ilog2( 5) = 2 | |||||
| * ilog2( 6) = 2 | |||||
| * ilog2( 7) = 2 | |||||
| * ilog2( 8) = 3 | |||||
| * ilog2( 9) = 3 | |||||
| * ilog2(10) = 3 | |||||
| * ilog2(11) = 3 | |||||
| * ilog2(12) = 3 | |||||
| * ilog2(13) = 3 | |||||
| * ilog2(14) = 3 | |||||
| * ilog2(15) = 3 | |||||
| * ilog2(16) = 4 | |||||
| * ilog2(17) = 4 | |||||
| * ilog2(18) = 4 | |||||
| */ | |||||
| unsigned FLAC__bitmath_ilog2(FLAC__uint32 v) | |||||
| { | |||||
| unsigned l = 0; | |||||
| FLAC__ASSERT(v > 0); | |||||
| while(v >>= 1) | |||||
| l++; | |||||
| return l; | |||||
| } | |||||
| unsigned FLAC__bitmath_ilog2_wide(FLAC__uint64 v) | |||||
| { | |||||
| unsigned l = 0; | |||||
| FLAC__ASSERT(v > 0); | |||||
| while(v >>= 1) | |||||
| l++; | |||||
| return l; | |||||
| } | |||||
| /* An example of what FLAC__bitmath_silog2() computes: | |||||
| * | |||||
| * silog2(-10) = 5 | |||||
| * silog2(- 9) = 5 | |||||
| * silog2(- 8) = 4 | |||||
| * silog2(- 7) = 4 | |||||
| * silog2(- 6) = 4 | |||||
| * silog2(- 5) = 4 | |||||
| * silog2(- 4) = 3 | |||||
| * silog2(- 3) = 3 | |||||
| * silog2(- 2) = 2 | |||||
| * silog2(- 1) = 2 | |||||
| * silog2( 0) = 0 | |||||
| * silog2( 1) = 2 | |||||
| * silog2( 2) = 3 | |||||
| * silog2( 3) = 3 | |||||
| * silog2( 4) = 4 | |||||
| * silog2( 5) = 4 | |||||
| * silog2( 6) = 4 | |||||
| * silog2( 7) = 4 | |||||
| * silog2( 8) = 5 | |||||
| * silog2( 9) = 5 | |||||
| * silog2( 10) = 5 | |||||
| */ | |||||
| unsigned FLAC__bitmath_silog2(int v) | |||||
| { | |||||
| while(1) { | |||||
| if(v == 0) { | |||||
| return 0; | |||||
| } | |||||
| else if(v > 0) { | |||||
| unsigned l = 0; | |||||
| while(v) { | |||||
| l++; | |||||
| v >>= 1; | |||||
| } | |||||
| return l+1; | |||||
| } | |||||
| else if(v == -1) { | |||||
| return 2; | |||||
| } | |||||
| else { | |||||
| v++; | |||||
| v = -v; | |||||
| } | |||||
| } | |||||
| } | |||||
| unsigned FLAC__bitmath_silog2_wide(FLAC__int64 v) | |||||
| { | |||||
| while(1) { | |||||
| if(v == 0) { | |||||
| return 0; | |||||
| } | |||||
| else if(v > 0) { | |||||
| unsigned l = 0; | |||||
| while(v) { | |||||
| l++; | |||||
| v >>= 1; | |||||
| } | |||||
| return l+1; | |||||
| } | |||||
| else if(v == -1) { | |||||
| return 2; | |||||
| } | |||||
| else { | |||||
| v++; | |||||
| v = -v; | |||||
| } | |||||
| } | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,885 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 "juce_FlacHeader.h" | |||||
| #if JUCE_USE_FLAC | |||||
| #if HAVE_CONFIG_H | |||||
| # include <config.h> | |||||
| #endif | |||||
| #include <stdlib.h> /* for malloc() */ | |||||
| #include <string.h> /* for memcpy(), memset() */ | |||||
| #ifdef _MSC_VER | |||||
| #include <winsock.h> /* for ntohl() */ | |||||
| #elif defined FLAC__SYS_DARWIN | |||||
| #include <machine/endian.h> /* for ntohl() */ | |||||
| #elif defined __MINGW32__ | |||||
| #include <winsock.h> /* for ntohl() */ | |||||
| #else | |||||
| #include <netinet/in.h> /* for ntohl() */ | |||||
| #endif | |||||
| #if 0 /* UNUSED */ | |||||
| #include "include/private/bitmath.h" | |||||
| #endif | |||||
| #include "include/private/bitwriter.h" | |||||
| #include "include/private/crc.h" | |||||
| #include "../assert.h" | |||||
| #include "../alloc.h" | |||||
| /* Things should be fastest when this matches the machine word size */ | |||||
| /* WATCHOUT: if you change this you must also change the following #defines down to SWAP_BE_WORD_TO_HOST below to match */ | |||||
| /* WATCHOUT: there are a few places where the code will not work unless bwword is >= 32 bits wide */ | |||||
| typedef FLAC__uint32 bwword; | |||||
| #define FLAC__BYTES_PER_WORD 4 | |||||
| #define FLAC__BITS_PER_WORD 32 | |||||
| #define FLAC__WORD_ALL_ONES ((FLAC__uint32)0xffffffff) | |||||
| /* SWAP_BE_WORD_TO_HOST swaps bytes in a bwword (which is always big-endian) if necessary to match host byte order */ | |||||
| #if WORDS_BIGENDIAN | |||||
| #define SWAP_BE_WORD_TO_HOST(x) (x) | |||||
| #else | |||||
| #ifdef _MSC_VER | |||||
| #define SWAP_BE_WORD_TO_HOST(x) local_swap32_(x) | |||||
| #else | |||||
| #define SWAP_BE_WORD_TO_HOST(x) ntohl(x) | |||||
| #endif | |||||
| #endif | |||||
| /* | |||||
| * The default capacity here doesn't matter too much. The buffer always grows | |||||
| * to hold whatever is written to it. Usually the encoder will stop adding at | |||||
| * a frame or metadata block, then write that out and clear the buffer for the | |||||
| * next one. | |||||
| */ | |||||
| static const unsigned FLAC__BITWRITER_DEFAULT_CAPACITY = 32768u / sizeof(bwword); /* size in words */ | |||||
| /* When growing, increment 4K at a time */ | |||||
| static const unsigned FLAC__BITWRITER_DEFAULT_INCREMENT = 4096u / sizeof(bwword); /* size in words */ | |||||
| #define FLAC__WORDS_TO_BITS(words) ((words) * FLAC__BITS_PER_WORD) | |||||
| #define FLAC__TOTAL_BITS(bw) (FLAC__WORDS_TO_BITS((bw)->words) + (bw)->bits) | |||||
| #ifdef min | |||||
| #undef min | |||||
| #endif | |||||
| #define min(x,y) ((x)<(y)?(x):(y)) | |||||
| /* adjust for compilers that can't understand using LLU suffix for uint64_t literals */ | |||||
| #ifdef _MSC_VER | |||||
| #define FLAC__U64L(x) x | |||||
| #else | |||||
| #define FLAC__U64L(x) x##LLU | |||||
| #endif | |||||
| #ifndef FLaC__INLINE | |||||
| #define FLaC__INLINE | |||||
| #endif | |||||
| struct FLAC__BitWriter { | |||||
| bwword *buffer; | |||||
| bwword accum; /* accumulator; bits are right-justified; when full, accum is appended to buffer */ | |||||
| unsigned capacity; /* capacity of buffer in words */ | |||||
| unsigned words; /* # of complete words in buffer */ | |||||
| unsigned bits; /* # of used bits in accum */ | |||||
| }; | |||||
| /* * WATCHOUT: The current implementation only grows the buffer. */ | |||||
| static FLAC__bool bitwriter_grow_(FLAC__BitWriter *bw, unsigned bits_to_add) | |||||
| { | |||||
| unsigned new_capacity; | |||||
| bwword *new_buffer; | |||||
| FLAC__ASSERT(0 != bw); | |||||
| FLAC__ASSERT(0 != bw->buffer); | |||||
| /* calculate total words needed to store 'bits_to_add' additional bits */ | |||||
| new_capacity = bw->words + ((bw->bits + bits_to_add + FLAC__BITS_PER_WORD - 1) / FLAC__BITS_PER_WORD); | |||||
| /* it's possible (due to pessimism in the growth estimation that | |||||
| * leads to this call) that we don't actually need to grow | |||||
| */ | |||||
| if(bw->capacity >= new_capacity) | |||||
| return true; | |||||
| /* round up capacity increase to the nearest FLAC__BITWRITER_DEFAULT_INCREMENT */ | |||||
| if((new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT) | |||||
| new_capacity += FLAC__BITWRITER_DEFAULT_INCREMENT - ((new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT); | |||||
| /* make sure we got everything right */ | |||||
| FLAC__ASSERT(0 == (new_capacity - bw->capacity) % FLAC__BITWRITER_DEFAULT_INCREMENT); | |||||
| FLAC__ASSERT(new_capacity > bw->capacity); | |||||
| FLAC__ASSERT(new_capacity >= bw->words + ((bw->bits + bits_to_add + FLAC__BITS_PER_WORD - 1) / FLAC__BITS_PER_WORD)); | |||||
| new_buffer = (bwword*)safe_realloc_mul_2op_(bw->buffer, sizeof(bwword), /*times*/new_capacity); | |||||
| if(new_buffer == 0) | |||||
| return false; | |||||
| bw->buffer = new_buffer; | |||||
| bw->capacity = new_capacity; | |||||
| return true; | |||||
| } | |||||
| /*********************************************************************** | |||||
| * | |||||
| * Class constructor/destructor | |||||
| * | |||||
| ***********************************************************************/ | |||||
| FLAC__BitWriter *FLAC__bitwriter_new(void) | |||||
| { | |||||
| FLAC__BitWriter *bw = (FLAC__BitWriter*)calloc(1, sizeof(FLAC__BitWriter)); | |||||
| /* note that calloc() sets all members to 0 for us */ | |||||
| return bw; | |||||
| } | |||||
| void FLAC__bitwriter_delete(FLAC__BitWriter *bw) | |||||
| { | |||||
| FLAC__ASSERT(0 != bw); | |||||
| FLAC__bitwriter_free(bw); | |||||
| free(bw); | |||||
| } | |||||
| /*********************************************************************** | |||||
| * | |||||
| * Public class methods | |||||
| * | |||||
| ***********************************************************************/ | |||||
| FLAC__bool FLAC__bitwriter_init(FLAC__BitWriter *bw) | |||||
| { | |||||
| FLAC__ASSERT(0 != bw); | |||||
| bw->words = bw->bits = 0; | |||||
| bw->capacity = FLAC__BITWRITER_DEFAULT_CAPACITY; | |||||
| bw->buffer = (bwword*)malloc(sizeof(bwword) * bw->capacity); | |||||
| if(bw->buffer == 0) | |||||
| return false; | |||||
| return true; | |||||
| } | |||||
| void FLAC__bitwriter_free(FLAC__BitWriter *bw) | |||||
| { | |||||
| FLAC__ASSERT(0 != bw); | |||||
| if(0 != bw->buffer) | |||||
| free(bw->buffer); | |||||
| bw->buffer = 0; | |||||
| bw->capacity = 0; | |||||
| bw->words = bw->bits = 0; | |||||
| } | |||||
| void FLAC__bitwriter_clear(FLAC__BitWriter *bw) | |||||
| { | |||||
| bw->words = bw->bits = 0; | |||||
| } | |||||
| void FLAC__bitwriter_dump(const FLAC__BitWriter *bw, FILE *out) | |||||
| { | |||||
| unsigned i, j; | |||||
| if(bw == 0) { | |||||
| fprintf(out, "bitwriter is NULL\n"); | |||||
| } | |||||
| else { | |||||
| fprintf(out, "bitwriter: capacity=%u words=%u bits=%u total_bits=%u\n", bw->capacity, bw->words, bw->bits, FLAC__TOTAL_BITS(bw)); | |||||
| for(i = 0; i < bw->words; i++) { | |||||
| fprintf(out, "%08X: ", i); | |||||
| for(j = 0; j < FLAC__BITS_PER_WORD; j++) | |||||
| fprintf(out, "%01u", bw->buffer[i] & (1 << (FLAC__BITS_PER_WORD-j-1)) ? 1:0); | |||||
| fprintf(out, "\n"); | |||||
| } | |||||
| if(bw->bits > 0) { | |||||
| fprintf(out, "%08X: ", i); | |||||
| for(j = 0; j < bw->bits; j++) | |||||
| fprintf(out, "%01u", bw->accum & (1 << (bw->bits-j-1)) ? 1:0); | |||||
| fprintf(out, "\n"); | |||||
| } | |||||
| } | |||||
| } | |||||
| FLAC__bool FLAC__bitwriter_get_write_crc16(FLAC__BitWriter *bw, FLAC__uint16 *crc) | |||||
| { | |||||
| const FLAC__byte *buffer; | |||||
| size_t bytes; | |||||
| FLAC__ASSERT((bw->bits & 7) == 0); /* assert that we're byte-aligned */ | |||||
| if(!FLAC__bitwriter_get_buffer(bw, &buffer, &bytes)) | |||||
| return false; | |||||
| *crc = (FLAC__uint16)FLAC__crc16(buffer, bytes); | |||||
| FLAC__bitwriter_release_buffer(bw); | |||||
| return true; | |||||
| } | |||||
| FLAC__bool FLAC__bitwriter_get_write_crc8(FLAC__BitWriter *bw, FLAC__byte *crc) | |||||
| { | |||||
| const FLAC__byte *buffer; | |||||
| size_t bytes; | |||||
| FLAC__ASSERT((bw->bits & 7) == 0); /* assert that we're byte-aligned */ | |||||
| if(!FLAC__bitwriter_get_buffer(bw, &buffer, &bytes)) | |||||
| return false; | |||||
| *crc = FLAC__crc8(buffer, bytes); | |||||
| FLAC__bitwriter_release_buffer(bw); | |||||
| return true; | |||||
| } | |||||
| FLAC__bool FLAC__bitwriter_is_byte_aligned(const FLAC__BitWriter *bw) | |||||
| { | |||||
| return ((bw->bits & 7) == 0); | |||||
| } | |||||
| unsigned FLAC__bitwriter_get_input_bits_unconsumed(const FLAC__BitWriter *bw) | |||||
| { | |||||
| return FLAC__TOTAL_BITS(bw); | |||||
| } | |||||
| FLAC__bool FLAC__bitwriter_get_buffer(FLAC__BitWriter *bw, const FLAC__byte **buffer, size_t *bytes) | |||||
| { | |||||
| FLAC__ASSERT((bw->bits & 7) == 0); | |||||
| /* double protection */ | |||||
| if(bw->bits & 7) | |||||
| return false; | |||||
| /* if we have bits in the accumulator we have to flush those to the buffer first */ | |||||
| if(bw->bits) { | |||||
| FLAC__ASSERT(bw->words <= bw->capacity); | |||||
| if(bw->words == bw->capacity && !bitwriter_grow_(bw, FLAC__BITS_PER_WORD)) | |||||
| return false; | |||||
| /* append bits as complete word to buffer, but don't change bw->accum or bw->bits */ | |||||
| bw->buffer[bw->words] = SWAP_BE_WORD_TO_HOST(bw->accum << (FLAC__BITS_PER_WORD-bw->bits)); | |||||
| } | |||||
| /* now we can just return what we have */ | |||||
| *buffer = (FLAC__byte*)bw->buffer; | |||||
| *bytes = (FLAC__BYTES_PER_WORD * bw->words) + (bw->bits >> 3); | |||||
| return true; | |||||
| } | |||||
| void FLAC__bitwriter_release_buffer(FLAC__BitWriter *bw) | |||||
| { | |||||
| /* nothing to do. in the future, strict checking of a 'writer-is-in- | |||||
| * get-mode' flag could be added everywhere and then cleared here | |||||
| */ | |||||
| (void)bw; | |||||
| } | |||||
| FLaC__INLINE FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, unsigned bits) | |||||
| { | |||||
| unsigned n; | |||||
| FLAC__ASSERT(0 != bw); | |||||
| FLAC__ASSERT(0 != bw->buffer); | |||||
| if(bits == 0) | |||||
| return true; | |||||
| /* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+bits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */ | |||||
| if(bw->capacity <= bw->words + bits && !bitwriter_grow_(bw, bits)) | |||||
| return false; | |||||
| /* first part gets to word alignment */ | |||||
| if(bw->bits) { | |||||
| n = min(FLAC__BITS_PER_WORD - bw->bits, bits); | |||||
| bw->accum <<= n; | |||||
| bits -= n; | |||||
| bw->bits += n; | |||||
| if(bw->bits == FLAC__BITS_PER_WORD) { | |||||
| bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); | |||||
| bw->bits = 0; | |||||
| } | |||||
| else | |||||
| return true; | |||||
| } | |||||
| /* do whole words */ | |||||
| while(bits >= FLAC__BITS_PER_WORD) { | |||||
| bw->buffer[bw->words++] = 0; | |||||
| bits -= FLAC__BITS_PER_WORD; | |||||
| } | |||||
| /* do any leftovers */ | |||||
| if(bits > 0) { | |||||
| bw->accum = 0; | |||||
| bw->bits = bits; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| FLaC__INLINE FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, unsigned bits) | |||||
| { | |||||
| register unsigned left; | |||||
| /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */ | |||||
| FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32); | |||||
| FLAC__ASSERT(0 != bw); | |||||
| FLAC__ASSERT(0 != bw->buffer); | |||||
| FLAC__ASSERT(bits <= 32); | |||||
| if(bits == 0) | |||||
| return true; | |||||
| /* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+bits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */ | |||||
| if(bw->capacity <= bw->words + bits && !bitwriter_grow_(bw, bits)) | |||||
| return false; | |||||
| left = FLAC__BITS_PER_WORD - bw->bits; | |||||
| if(bits < left) { | |||||
| bw->accum <<= bits; | |||||
| bw->accum |= val; | |||||
| bw->bits += bits; | |||||
| } | |||||
| else if(bw->bits) { /* WATCHOUT: if bw->bits == 0, left==FLAC__BITS_PER_WORD and bw->accum<<=left is a NOP instead of setting to 0 */ | |||||
| bw->accum <<= left; | |||||
| bw->accum |= val >> (bw->bits = bits - left); | |||||
| bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); | |||||
| bw->accum = val; | |||||
| } | |||||
| else { | |||||
| bw->accum = val; | |||||
| bw->bits = 0; | |||||
| bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(val); | |||||
| } | |||||
| return true; | |||||
| } | |||||
| FLaC__INLINE FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, unsigned bits) | |||||
| { | |||||
| /* zero-out unused bits */ | |||||
| if(bits < 32) | |||||
| val &= (~(0xffffffff << bits)); | |||||
| return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, bits); | |||||
| } | |||||
| FLaC__INLINE FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, unsigned bits) | |||||
| { | |||||
| /* this could be a little faster but it's not used for much */ | |||||
| if(bits > 32) { | |||||
| return | |||||
| FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)(val>>32), bits-32) && | |||||
| FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, 32); | |||||
| } | |||||
| else | |||||
| return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, bits); | |||||
| } | |||||
| FLaC__INLINE FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val) | |||||
| { | |||||
| /* this doesn't need to be that fast as currently it is only used for vorbis comments */ | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, val & 0xff, 8)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, (val>>8) & 0xff, 8)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, (val>>16) & 0xff, 8)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, val>>24, 8)) | |||||
| return false; | |||||
| return true; | |||||
| } | |||||
| FLaC__INLINE FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], unsigned nvals) | |||||
| { | |||||
| unsigned i; | |||||
| /* this could be faster but currently we don't need it to be since it's only used for writing metadata */ | |||||
| for(i = 0; i < nvals; i++) { | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)(vals[i]), 8)) | |||||
| return false; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, unsigned val) | |||||
| { | |||||
| if(val < 32) | |||||
| return FLAC__bitwriter_write_raw_uint32(bw, 1, ++val); | |||||
| else | |||||
| return | |||||
| FLAC__bitwriter_write_zeroes(bw, val) && | |||||
| FLAC__bitwriter_write_raw_uint32(bw, 1, 1); | |||||
| } | |||||
| unsigned FLAC__bitwriter_rice_bits(FLAC__int32 val, unsigned parameter) | |||||
| { | |||||
| FLAC__uint32 uval; | |||||
| FLAC__ASSERT(parameter < sizeof(unsigned)*8); | |||||
| /* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */ | |||||
| uval = (val<<1) ^ (val>>31); | |||||
| return 1 + parameter + (uval >> parameter); | |||||
| } | |||||
| #if 0 /* UNUSED */ | |||||
| unsigned FLAC__bitwriter_golomb_bits_signed(int val, unsigned parameter) | |||||
| { | |||||
| unsigned bits, msbs, uval; | |||||
| unsigned k; | |||||
| FLAC__ASSERT(parameter > 0); | |||||
| /* fold signed to unsigned */ | |||||
| if(val < 0) | |||||
| uval = (unsigned)(((-(++val)) << 1) + 1); | |||||
| else | |||||
| uval = (unsigned)(val << 1); | |||||
| k = FLAC__bitmath_ilog2(parameter); | |||||
| if(parameter == 1u<<k) { | |||||
| FLAC__ASSERT(k <= 30); | |||||
| msbs = uval >> k; | |||||
| bits = 1 + k + msbs; | |||||
| } | |||||
| else { | |||||
| unsigned q, r, d; | |||||
| d = (1 << (k+1)) - parameter; | |||||
| q = uval / parameter; | |||||
| r = uval - (q * parameter); | |||||
| bits = 1 + q + k; | |||||
| if(r >= d) | |||||
| bits++; | |||||
| } | |||||
| return bits; | |||||
| } | |||||
| unsigned FLAC__bitwriter_golomb_bits_unsigned(unsigned uval, unsigned parameter) | |||||
| { | |||||
| unsigned bits, msbs; | |||||
| unsigned k; | |||||
| FLAC__ASSERT(parameter > 0); | |||||
| k = FLAC__bitmath_ilog2(parameter); | |||||
| if(parameter == 1u<<k) { | |||||
| FLAC__ASSERT(k <= 30); | |||||
| msbs = uval >> k; | |||||
| bits = 1 + k + msbs; | |||||
| } | |||||
| else { | |||||
| unsigned q, r, d; | |||||
| d = (1 << (k+1)) - parameter; | |||||
| q = uval / parameter; | |||||
| r = uval - (q * parameter); | |||||
| bits = 1 + q + k; | |||||
| if(r >= d) | |||||
| bits++; | |||||
| } | |||||
| return bits; | |||||
| } | |||||
| #endif /* UNUSED */ | |||||
| FLAC__bool FLAC__bitwriter_write_rice_signed(FLAC__BitWriter *bw, FLAC__int32 val, unsigned parameter) | |||||
| { | |||||
| unsigned total_bits, interesting_bits, msbs; | |||||
| FLAC__uint32 uval, pattern; | |||||
| FLAC__ASSERT(0 != bw); | |||||
| FLAC__ASSERT(0 != bw->buffer); | |||||
| FLAC__ASSERT(parameter < 8*sizeof(uval)); | |||||
| /* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */ | |||||
| uval = (val<<1) ^ (val>>31); | |||||
| msbs = uval >> parameter; | |||||
| interesting_bits = 1 + parameter; | |||||
| total_bits = interesting_bits + msbs; | |||||
| pattern = 1 << parameter; /* the unary end bit */ | |||||
| pattern |= (uval & ((1<<parameter)-1)); /* the binary LSBs */ | |||||
| if(total_bits <= 32) | |||||
| return FLAC__bitwriter_write_raw_uint32(bw, pattern, total_bits); | |||||
| else | |||||
| return | |||||
| FLAC__bitwriter_write_zeroes(bw, msbs) && /* write the unary MSBs */ | |||||
| FLAC__bitwriter_write_raw_uint32(bw, pattern, interesting_bits); /* write the unary end bit and binary LSBs */ | |||||
| } | |||||
| FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FLAC__int32 *vals, unsigned nvals, unsigned parameter) | |||||
| { | |||||
| const FLAC__uint32 mask1 = FLAC__WORD_ALL_ONES << parameter; /* we val|=mask1 to set the stop bit above it... */ | |||||
| const FLAC__uint32 mask2 = FLAC__WORD_ALL_ONES >> (31-parameter); /* ...then mask off the bits above the stop bit with val&=mask2*/ | |||||
| FLAC__uint32 uval; | |||||
| unsigned left; | |||||
| const unsigned lsbits = 1 + parameter; | |||||
| unsigned msbits; | |||||
| FLAC__ASSERT(0 != bw); | |||||
| FLAC__ASSERT(0 != bw->buffer); | |||||
| FLAC__ASSERT(parameter < 8*sizeof(bwword)-1); | |||||
| /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */ | |||||
| FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32); | |||||
| while(nvals) { | |||||
| /* fold signed to unsigned; actual formula is: negative(v)? -2v-1 : 2v */ | |||||
| uval = (*vals<<1) ^ (*vals>>31); | |||||
| msbits = uval >> parameter; | |||||
| #if 0 /* OPT: can remove this special case if it doesn't make up for the extra compare (doesn't make a statistically significant difference with msvc or gcc/x86) */ | |||||
| if(bw->bits && bw->bits + msbits + lsbits <= FLAC__BITS_PER_WORD) { /* i.e. if the whole thing fits in the current bwword */ | |||||
| /* ^^^ if bw->bits is 0 then we may have filled the buffer and have no free bwword to work in */ | |||||
| bw->bits = bw->bits + msbits + lsbits; | |||||
| uval |= mask1; /* set stop bit */ | |||||
| uval &= mask2; /* mask off unused top bits */ | |||||
| /* NOT: bw->accum <<= msbits + lsbits because msbits+lsbits could be 32, then the shift would be a NOP */ | |||||
| bw->accum <<= msbits; | |||||
| bw->accum <<= lsbits; | |||||
| bw->accum |= uval; | |||||
| if(bw->bits == FLAC__BITS_PER_WORD) { | |||||
| bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); | |||||
| bw->bits = 0; | |||||
| /* burying the capacity check down here means we have to grow the buffer a little if there are more vals to do */ | |||||
| if(bw->capacity <= bw->words && nvals > 1 && !bitwriter_grow_(bw, 1)) { | |||||
| FLAC__ASSERT(bw->capacity == bw->words); | |||||
| return false; | |||||
| } | |||||
| } | |||||
| } | |||||
| else { | |||||
| #elif 1 /*@@@@@@ OPT: try this version with MSVC6 to see if better, not much difference for gcc-4 */ | |||||
| if(bw->bits && bw->bits + msbits + lsbits < FLAC__BITS_PER_WORD) { /* i.e. if the whole thing fits in the current bwword */ | |||||
| /* ^^^ if bw->bits is 0 then we may have filled the buffer and have no free bwword to work in */ | |||||
| bw->bits = bw->bits + msbits + lsbits; | |||||
| uval |= mask1; /* set stop bit */ | |||||
| uval &= mask2; /* mask off unused top bits */ | |||||
| bw->accum <<= msbits + lsbits; | |||||
| bw->accum |= uval; | |||||
| } | |||||
| else { | |||||
| #endif | |||||
| /* slightly pessimistic size check but faster than "<= bw->words + (bw->bits+msbits+lsbits+FLAC__BITS_PER_WORD-1)/FLAC__BITS_PER_WORD" */ | |||||
| /* OPT: pessimism may cause flurry of false calls to grow_ which eat up all savings before it */ | |||||
| if(bw->capacity <= bw->words + bw->bits + msbits + 1/*lsbits always fit in 1 bwword*/ && !bitwriter_grow_(bw, msbits+lsbits)) | |||||
| return false; | |||||
| if(msbits) { | |||||
| /* first part gets to word alignment */ | |||||
| if(bw->bits) { | |||||
| left = FLAC__BITS_PER_WORD - bw->bits; | |||||
| if(msbits < left) { | |||||
| bw->accum <<= msbits; | |||||
| bw->bits += msbits; | |||||
| goto break1; | |||||
| } | |||||
| else { | |||||
| bw->accum <<= left; | |||||
| msbits -= left; | |||||
| bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); | |||||
| bw->bits = 0; | |||||
| } | |||||
| } | |||||
| /* do whole words */ | |||||
| while(msbits >= FLAC__BITS_PER_WORD) { | |||||
| bw->buffer[bw->words++] = 0; | |||||
| msbits -= FLAC__BITS_PER_WORD; | |||||
| } | |||||
| /* do any leftovers */ | |||||
| if(msbits > 0) { | |||||
| bw->accum = 0; | |||||
| bw->bits = msbits; | |||||
| } | |||||
| } | |||||
| break1: | |||||
| uval |= mask1; /* set stop bit */ | |||||
| uval &= mask2; /* mask off unused top bits */ | |||||
| left = FLAC__BITS_PER_WORD - bw->bits; | |||||
| if(lsbits < left) { | |||||
| bw->accum <<= lsbits; | |||||
| bw->accum |= uval; | |||||
| bw->bits += lsbits; | |||||
| } | |||||
| else { | |||||
| /* if bw->bits == 0, left==FLAC__BITS_PER_WORD which will always | |||||
| * be > lsbits (because of previous assertions) so it would have | |||||
| * triggered the (lsbits<left) case above. | |||||
| */ | |||||
| FLAC__ASSERT(bw->bits); | |||||
| FLAC__ASSERT(left < FLAC__BITS_PER_WORD); | |||||
| bw->accum <<= left; | |||||
| bw->accum |= uval >> (bw->bits = lsbits - left); | |||||
| bw->buffer[bw->words++] = SWAP_BE_WORD_TO_HOST(bw->accum); | |||||
| bw->accum = uval; | |||||
| } | |||||
| #if 1 | |||||
| } | |||||
| #endif | |||||
| vals++; | |||||
| nvals--; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| #if 0 /* UNUSED */ | |||||
| FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, unsigned parameter) | |||||
| { | |||||
| unsigned total_bits, msbs, uval; | |||||
| unsigned k; | |||||
| FLAC__ASSERT(0 != bw); | |||||
| FLAC__ASSERT(0 != bw->buffer); | |||||
| FLAC__ASSERT(parameter > 0); | |||||
| /* fold signed to unsigned */ | |||||
| if(val < 0) | |||||
| uval = (unsigned)(((-(++val)) << 1) + 1); | |||||
| else | |||||
| uval = (unsigned)(val << 1); | |||||
| k = FLAC__bitmath_ilog2(parameter); | |||||
| if(parameter == 1u<<k) { | |||||
| unsigned pattern; | |||||
| FLAC__ASSERT(k <= 30); | |||||
| msbs = uval >> k; | |||||
| total_bits = 1 + k + msbs; | |||||
| pattern = 1 << k; /* the unary end bit */ | |||||
| pattern |= (uval & ((1u<<k)-1)); /* the binary LSBs */ | |||||
| if(total_bits <= 32) { | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, total_bits)) | |||||
| return false; | |||||
| } | |||||
| else { | |||||
| /* write the unary MSBs */ | |||||
| if(!FLAC__bitwriter_write_zeroes(bw, msbs)) | |||||
| return false; | |||||
| /* write the unary end bit and binary LSBs */ | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, k+1)) | |||||
| return false; | |||||
| } | |||||
| } | |||||
| else { | |||||
| unsigned q, r, d; | |||||
| d = (1 << (k+1)) - parameter; | |||||
| q = uval / parameter; | |||||
| r = uval - (q * parameter); | |||||
| /* write the unary MSBs */ | |||||
| if(!FLAC__bitwriter_write_zeroes(bw, q)) | |||||
| return false; | |||||
| /* write the unary end bit */ | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, 1, 1)) | |||||
| return false; | |||||
| /* write the binary LSBs */ | |||||
| if(r >= d) { | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, r+d, k+1)) | |||||
| return false; | |||||
| } | |||||
| else { | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, r, k)) | |||||
| return false; | |||||
| } | |||||
| } | |||||
| return true; | |||||
| } | |||||
| FLAC__bool FLAC__bitwriter_write_golomb_unsigned(FLAC__BitWriter *bw, unsigned uval, unsigned parameter) | |||||
| { | |||||
| unsigned total_bits, msbs; | |||||
| unsigned k; | |||||
| FLAC__ASSERT(0 != bw); | |||||
| FLAC__ASSERT(0 != bw->buffer); | |||||
| FLAC__ASSERT(parameter > 0); | |||||
| k = FLAC__bitmath_ilog2(parameter); | |||||
| if(parameter == 1u<<k) { | |||||
| unsigned pattern; | |||||
| FLAC__ASSERT(k <= 30); | |||||
| msbs = uval >> k; | |||||
| total_bits = 1 + k + msbs; | |||||
| pattern = 1 << k; /* the unary end bit */ | |||||
| pattern |= (uval & ((1u<<k)-1)); /* the binary LSBs */ | |||||
| if(total_bits <= 32) { | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, total_bits)) | |||||
| return false; | |||||
| } | |||||
| else { | |||||
| /* write the unary MSBs */ | |||||
| if(!FLAC__bitwriter_write_zeroes(bw, msbs)) | |||||
| return false; | |||||
| /* write the unary end bit and binary LSBs */ | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, pattern, k+1)) | |||||
| return false; | |||||
| } | |||||
| } | |||||
| else { | |||||
| unsigned q, r, d; | |||||
| d = (1 << (k+1)) - parameter; | |||||
| q = uval / parameter; | |||||
| r = uval - (q * parameter); | |||||
| /* write the unary MSBs */ | |||||
| if(!FLAC__bitwriter_write_zeroes(bw, q)) | |||||
| return false; | |||||
| /* write the unary end bit */ | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, 1, 1)) | |||||
| return false; | |||||
| /* write the binary LSBs */ | |||||
| if(r >= d) { | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, r+d, k+1)) | |||||
| return false; | |||||
| } | |||||
| else { | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, r, k)) | |||||
| return false; | |||||
| } | |||||
| } | |||||
| return true; | |||||
| } | |||||
| #endif /* UNUSED */ | |||||
| FLAC__bool FLAC__bitwriter_write_utf8_uint32(FLAC__BitWriter *bw, FLAC__uint32 val) | |||||
| { | |||||
| FLAC__bool ok = 1; | |||||
| FLAC__ASSERT(0 != bw); | |||||
| FLAC__ASSERT(0 != bw->buffer); | |||||
| FLAC__ASSERT(!(val & 0x80000000)); /* this version only handles 31 bits */ | |||||
| if(val < 0x80) { | |||||
| return FLAC__bitwriter_write_raw_uint32(bw, val, 8); | |||||
| } | |||||
| else if(val < 0x800) { | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xC0 | (val>>6), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8); | |||||
| } | |||||
| else if(val < 0x10000) { | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xE0 | (val>>12), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8); | |||||
| } | |||||
| else if(val < 0x200000) { | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF0 | (val>>18), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>12)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8); | |||||
| } | |||||
| else if(val < 0x4000000) { | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF8 | (val>>24), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>18)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>12)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8); | |||||
| } | |||||
| else { | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xFC | (val>>30), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>24)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>18)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>12)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | ((val>>6)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (val&0x3F), 8); | |||||
| } | |||||
| return ok; | |||||
| } | |||||
| FLAC__bool FLAC__bitwriter_write_utf8_uint64(FLAC__BitWriter *bw, FLAC__uint64 val) | |||||
| { | |||||
| FLAC__bool ok = 1; | |||||
| FLAC__ASSERT(0 != bw); | |||||
| FLAC__ASSERT(0 != bw->buffer); | |||||
| FLAC__ASSERT(!(val & FLAC__U64L(0xFFFFFFF000000000))); /* this version only handles 36 bits */ | |||||
| if(val < 0x80) { | |||||
| return FLAC__bitwriter_write_raw_uint32(bw, (FLAC__uint32)val, 8); | |||||
| } | |||||
| else if(val < 0x800) { | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xC0 | (FLAC__uint32)(val>>6), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); | |||||
| } | |||||
| else if(val < 0x10000) { | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xE0 | (FLAC__uint32)(val>>12), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); | |||||
| } | |||||
| else if(val < 0x200000) { | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF0 | (FLAC__uint32)(val>>18), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); | |||||
| } | |||||
| else if(val < 0x4000000) { | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xF8 | (FLAC__uint32)(val>>24), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); | |||||
| } | |||||
| else if(val < 0x80000000) { | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xFC | (FLAC__uint32)(val>>30), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); | |||||
| } | |||||
| else { | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0xFE, 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>30)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>24)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>18)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>12)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)((val>>6)&0x3F), 8); | |||||
| ok &= FLAC__bitwriter_write_raw_uint32(bw, 0x80 | (FLAC__uint32)(val&0x3F), 8); | |||||
| } | |||||
| return ok; | |||||
| } | |||||
| FLAC__bool FLAC__bitwriter_zero_pad_to_byte_boundary(FLAC__BitWriter *bw) | |||||
| { | |||||
| /* 0-pad to byte boundary */ | |||||
| if(bw->bits & 7u) | |||||
| return FLAC__bitwriter_write_zeroes(bw, 8 - (bw->bits & 7u)); | |||||
| else | |||||
| return true; | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,423 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 "juce_FlacHeader.h" | |||||
| #if JUCE_USE_FLAC | |||||
| #if HAVE_CONFIG_H | |||||
| # include <config.h> | |||||
| #endif | |||||
| #include "include/private/cpu.h" | |||||
| #include <stdlib.h> | |||||
| #include <stdio.h> | |||||
| #if defined FLAC__CPU_IA32 | |||||
| # include <signal.h> | |||||
| #elif defined FLAC__CPU_PPC | |||||
| # if !defined FLAC__NO_ASM | |||||
| # if defined FLAC__SYS_DARWIN | |||||
| # include <sys/sysctl.h> | |||||
| # include <mach/mach.h> | |||||
| # include <mach/mach_host.h> | |||||
| # include <mach/host_info.h> | |||||
| # include <mach/machine.h> | |||||
| # ifndef CPU_SUBTYPE_POWERPC_970 | |||||
| # define CPU_SUBTYPE_POWERPC_970 ((cpu_subtype_t) 100) | |||||
| # endif | |||||
| # else /* FLAC__SYS_DARWIN */ | |||||
| # include <signal.h> | |||||
| # include <setjmp.h> | |||||
| static sigjmp_buf jmpbuf; | |||||
| static volatile sig_atomic_t canjump = 0; | |||||
| static void sigill_handler (int sig) | |||||
| { | |||||
| if (!canjump) { | |||||
| signal (sig, SIG_DFL); | |||||
| raise (sig); | |||||
| } | |||||
| canjump = 0; | |||||
| siglongjmp (jmpbuf, 1); | |||||
| } | |||||
| # endif /* FLAC__SYS_DARWIN */ | |||||
| # endif /* FLAC__NO_ASM */ | |||||
| #endif /* FLAC__CPU_PPC */ | |||||
| #if defined (__NetBSD__) || defined(__OpenBSD__) | |||||
| #include <sys/param.h> | |||||
| #include <sys/sysctl.h> | |||||
| #include <machine/cpu.h> | |||||
| #endif | |||||
| #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) | |||||
| #include <sys/types.h> | |||||
| #include <sys/sysctl.h> | |||||
| #endif | |||||
| #if defined(__APPLE__) | |||||
| /* how to get sysctlbyname()? */ | |||||
| #endif | |||||
| /* these are flags in EDX of CPUID AX=00000001 */ | |||||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_CMOV = 0x00008000; | |||||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_MMX = 0x00800000; | |||||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_FXSR = 0x01000000; | |||||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE = 0x02000000; | |||||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE2 = 0x04000000; | |||||
| /* these are flags in ECX of CPUID AX=00000001 */ | |||||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_SSE3 = 0x00000001; | |||||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_SSSE3 = 0x00000200; | |||||
| /* these are flags in EDX of CPUID AX=80000001 */ | |||||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW = 0x80000000; | |||||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW = 0x40000000; | |||||
| static const unsigned FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX = 0x00400000; | |||||
| /* | |||||
| * Extra stuff needed for detection of OS support for SSE on IA-32 | |||||
| */ | |||||
| #if defined(FLAC__CPU_IA32) && !defined FLAC__NO_ASM && defined FLAC__HAS_NASM && !defined FLAC__NO_SSE_OS && !defined FLAC__SSE_OS | |||||
| # if defined(__linux__) | |||||
| /* | |||||
| * If the OS doesn't support SSE, we will get here with a SIGILL. We | |||||
| * modify the return address to jump over the offending SSE instruction | |||||
| * and also the operation following it that indicates the instruction | |||||
| * executed successfully. In this way we use no global variables and | |||||
| * stay thread-safe. | |||||
| * | |||||
| * 3 + 3 + 6: | |||||
| * 3 bytes for "xorps xmm0,xmm0" | |||||
| * 3 bytes for estimate of how long the follwing "inc var" instruction is | |||||
| * 6 bytes extra in case our estimate is wrong | |||||
| * 12 bytes puts us in the NOP "landing zone" | |||||
| */ | |||||
| # undef USE_OBSOLETE_SIGCONTEXT_FLAVOR /* #define this to use the older signal handler method */ | |||||
| # ifdef USE_OBSOLETE_SIGCONTEXT_FLAVOR | |||||
| static void sigill_handler_sse_os(int signal, struct sigcontext sc) | |||||
| { | |||||
| (void)signal; | |||||
| sc.eip += 3 + 3 + 6; | |||||
| } | |||||
| # else | |||||
| # include <sys/ucontext.h> | |||||
| static void sigill_handler_sse_os(int signal, siginfo_t *si, void *uc) | |||||
| { | |||||
| (void)signal, (void)si; | |||||
| ((ucontext_t*)uc)->uc_mcontext.gregs[14/*REG_EIP*/] += 3 + 3 + 6; | |||||
| } | |||||
| # endif | |||||
| # elif defined(_MSC_VER) | |||||
| # include <windows.h> | |||||
| # undef USE_TRY_CATCH_FLAVOR /* #define this to use the try/catch method for catching illegal opcode exception */ | |||||
| # ifdef USE_TRY_CATCH_FLAVOR | |||||
| # else | |||||
| LONG CALLBACK sigill_handler_sse_os(EXCEPTION_POINTERS *ep) | |||||
| { | |||||
| if(ep->ExceptionRecord->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION) { | |||||
| ep->ContextRecord->Eip += 3 + 3 + 6; | |||||
| return EXCEPTION_CONTINUE_EXECUTION; | |||||
| } | |||||
| return EXCEPTION_CONTINUE_SEARCH; | |||||
| } | |||||
| # endif | |||||
| # endif | |||||
| #endif | |||||
| void FLAC__cpu_info(FLAC__CPUInfo *info) | |||||
| { | |||||
| /* | |||||
| * IA32-specific | |||||
| */ | |||||
| #ifdef FLAC__CPU_IA32 | |||||
| info->type = FLAC__CPUINFO_TYPE_IA32; | |||||
| #if !defined FLAC__NO_ASM && defined FLAC__HAS_NASM | |||||
| info->use_asm = true; /* we assume a minimum of 80386 with FLAC__CPU_IA32 */ | |||||
| info->data.ia32.cpuid = FLAC__cpu_have_cpuid_asm_ia32()? true : false; | |||||
| info->data.ia32.bswap = info->data.ia32.cpuid; /* CPUID => BSWAP since it came after */ | |||||
| info->data.ia32.cmov = false; | |||||
| info->data.ia32.mmx = false; | |||||
| info->data.ia32.fxsr = false; | |||||
| info->data.ia32.sse = false; | |||||
| info->data.ia32.sse2 = false; | |||||
| info->data.ia32.sse3 = false; | |||||
| info->data.ia32.ssse3 = false; | |||||
| info->data.ia32._3dnow = false; | |||||
| info->data.ia32.ext3dnow = false; | |||||
| info->data.ia32.extmmx = false; | |||||
| if(info->data.ia32.cpuid) { | |||||
| /* http://www.sandpile.org/ia32/cpuid.htm */ | |||||
| FLAC__uint32 flags_edx, flags_ecx; | |||||
| FLAC__cpu_info_asm_ia32(&flags_edx, &flags_ecx); | |||||
| info->data.ia32.cmov = (flags_edx & FLAC__CPUINFO_IA32_CPUID_CMOV )? true : false; | |||||
| info->data.ia32.mmx = (flags_edx & FLAC__CPUINFO_IA32_CPUID_MMX )? true : false; | |||||
| info->data.ia32.fxsr = (flags_edx & FLAC__CPUINFO_IA32_CPUID_FXSR )? true : false; | |||||
| info->data.ia32.sse = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE )? true : false; | |||||
| info->data.ia32.sse2 = (flags_edx & FLAC__CPUINFO_IA32_CPUID_SSE2 )? true : false; | |||||
| info->data.ia32.sse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSE3 )? true : false; | |||||
| info->data.ia32.ssse3 = (flags_ecx & FLAC__CPUINFO_IA32_CPUID_SSSE3)? true : false; | |||||
| #ifdef FLAC__USE_3DNOW | |||||
| flags_edx = FLAC__cpu_info_extended_amd_asm_ia32(); | |||||
| info->data.ia32._3dnow = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_3DNOW )? true : false; | |||||
| info->data.ia32.ext3dnow = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXT3DNOW)? true : false; | |||||
| info->data.ia32.extmmx = (flags_edx & FLAC__CPUINFO_IA32_CPUID_EXTENDED_AMD_EXTMMX )? true : false; | |||||
| #else | |||||
| info->data.ia32._3dnow = info->data.ia32.ext3dnow = info->data.ia32.extmmx = false; | |||||
| #endif | |||||
| #ifdef DEBUG | |||||
| fprintf(stderr, "CPU info (IA-32):\n"); | |||||
| fprintf(stderr, " CPUID ...... %c\n", info->data.ia32.cpuid ? 'Y' : 'n'); | |||||
| fprintf(stderr, " BSWAP ...... %c\n", info->data.ia32.bswap ? 'Y' : 'n'); | |||||
| fprintf(stderr, " CMOV ....... %c\n", info->data.ia32.cmov ? 'Y' : 'n'); | |||||
| fprintf(stderr, " MMX ........ %c\n", info->data.ia32.mmx ? 'Y' : 'n'); | |||||
| fprintf(stderr, " FXSR ....... %c\n", info->data.ia32.fxsr ? 'Y' : 'n'); | |||||
| fprintf(stderr, " SSE ........ %c\n", info->data.ia32.sse ? 'Y' : 'n'); | |||||
| fprintf(stderr, " SSE2 ....... %c\n", info->data.ia32.sse2 ? 'Y' : 'n'); | |||||
| fprintf(stderr, " SSE3 ....... %c\n", info->data.ia32.sse3 ? 'Y' : 'n'); | |||||
| fprintf(stderr, " SSSE3 ...... %c\n", info->data.ia32.ssse3 ? 'Y' : 'n'); | |||||
| fprintf(stderr, " 3DNow! ..... %c\n", info->data.ia32._3dnow ? 'Y' : 'n'); | |||||
| fprintf(stderr, " 3DNow!-ext . %c\n", info->data.ia32.ext3dnow? 'Y' : 'n'); | |||||
| fprintf(stderr, " 3DNow!-MMX . %c\n", info->data.ia32.extmmx ? 'Y' : 'n'); | |||||
| #endif | |||||
| /* | |||||
| * now have to check for OS support of SSE/SSE2 | |||||
| */ | |||||
| if(info->data.ia32.fxsr || info->data.ia32.sse || info->data.ia32.sse2) { | |||||
| #if defined FLAC__NO_SSE_OS | |||||
| /* assume user knows better than us; turn it off */ | |||||
| info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false; | |||||
| #elif defined FLAC__SSE_OS | |||||
| /* assume user knows better than us; leave as detected above */ | |||||
| #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__) || defined(__APPLE__) | |||||
| int sse = 0; | |||||
| size_t len; | |||||
| /* at least one of these must work: */ | |||||
| len = sizeof(sse); sse = sse || (sysctlbyname("hw.instruction_sse", &sse, &len, NULL, 0) == 0 && sse); | |||||
| len = sizeof(sse); sse = sse || (sysctlbyname("hw.optional.sse" , &sse, &len, NULL, 0) == 0 && sse); /* __APPLE__ ? */ | |||||
| if(!sse) | |||||
| info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false; | |||||
| #elif defined(__NetBSD__) || defined (__OpenBSD__) | |||||
| # if __NetBSD_Version__ >= 105250000 || (defined __OpenBSD__) | |||||
| int val = 0, mib[2] = { CTL_MACHDEP, CPU_SSE }; | |||||
| size_t len = sizeof(val); | |||||
| if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val) | |||||
| info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false; | |||||
| else { /* double-check SSE2 */ | |||||
| mib[1] = CPU_SSE2; | |||||
| len = sizeof(val); | |||||
| if(sysctl(mib, 2, &val, &len, NULL, 0) < 0 || !val) | |||||
| info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false; | |||||
| } | |||||
| # else | |||||
| info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false; | |||||
| # endif | |||||
| #elif defined(__linux__) | |||||
| int sse = 0; | |||||
| struct sigaction sigill_save; | |||||
| #ifdef USE_OBSOLETE_SIGCONTEXT_FLAVOR | |||||
| if(0 == sigaction(SIGILL, NULL, &sigill_save) && signal(SIGILL, (void (*)(int))sigill_handler_sse_os) != SIG_ERR) | |||||
| #else | |||||
| struct sigaction sigill_sse; | |||||
| sigill_sse.sa_sigaction = sigill_handler_sse_os; | |||||
| __sigemptyset(&sigill_sse.sa_mask); | |||||
| sigill_sse.sa_flags = SA_SIGINFO | SA_RESETHAND; /* SA_RESETHAND just in case our SIGILL return jump breaks, so we don't get stuck in a loop */ | |||||
| if(0 == sigaction(SIGILL, &sigill_sse, &sigill_save)) | |||||
| #endif | |||||
| { | |||||
| /* http://www.ibiblio.org/gferg/ldp/GCC-Inline-Assembly-HOWTO.html */ | |||||
| /* see sigill_handler_sse_os() for an explanation of the following: */ | |||||
| asm volatile ( | |||||
| "xorl %0,%0\n\t" /* for some reason, still need to do this to clear 'sse' var */ | |||||
| "xorps %%xmm0,%%xmm0\n\t" /* will cause SIGILL if unsupported by OS */ | |||||
| "incl %0\n\t" /* SIGILL handler will jump over this */ | |||||
| /* landing zone */ | |||||
| "nop\n\t" /* SIGILL jump lands here if "inc" is 9 bytes */ | |||||
| "nop\n\t" | |||||
| "nop\n\t" | |||||
| "nop\n\t" | |||||
| "nop\n\t" | |||||
| "nop\n\t" | |||||
| "nop\n\t" /* SIGILL jump lands here if "inc" is 3 bytes (expected) */ | |||||
| "nop\n\t" | |||||
| "nop" /* SIGILL jump lands here if "inc" is 1 byte */ | |||||
| : "=r"(sse) | |||||
| : "r"(sse) | |||||
| ); | |||||
| sigaction(SIGILL, &sigill_save, NULL); | |||||
| } | |||||
| if(!sse) | |||||
| info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false; | |||||
| #elif defined(_MSC_VER) | |||||
| # ifdef USE_TRY_CATCH_FLAVOR | |||||
| _try { | |||||
| __asm { | |||||
| # if _MSC_VER <= 1200 | |||||
| /* VC6 assembler doesn't know SSE, have to emit bytecode instead */ | |||||
| _emit 0x0F | |||||
| _emit 0x57 | |||||
| _emit 0xC0 | |||||
| # else | |||||
| xorps xmm0,xmm0 | |||||
| # endif | |||||
| } | |||||
| } | |||||
| _except(EXCEPTION_EXECUTE_HANDLER) { | |||||
| if (_exception_code() == STATUS_ILLEGAL_INSTRUCTION) | |||||
| info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false; | |||||
| } | |||||
| # else | |||||
| int sse = 0; | |||||
| LPTOP_LEVEL_EXCEPTION_FILTER save = SetUnhandledExceptionFilter(sigill_handler_sse_os); | |||||
| /* see GCC version above for explanation */ | |||||
| /* http://msdn2.microsoft.com/en-us/library/4ks26t93.aspx */ | |||||
| /* http://www.codeproject.com/cpp/gccasm.asp */ | |||||
| /* http://www.hick.org/~mmiller/msvc_inline_asm.html */ | |||||
| __asm { | |||||
| # if _MSC_VER <= 1200 | |||||
| /* VC6 assembler doesn't know SSE, have to emit bytecode instead */ | |||||
| _emit 0x0F | |||||
| _emit 0x57 | |||||
| _emit 0xC0 | |||||
| # else | |||||
| xorps xmm0,xmm0 | |||||
| # endif | |||||
| inc sse | |||||
| nop | |||||
| nop | |||||
| nop | |||||
| nop | |||||
| nop | |||||
| nop | |||||
| nop | |||||
| nop | |||||
| nop | |||||
| } | |||||
| SetUnhandledExceptionFilter(save); | |||||
| if(!sse) | |||||
| info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false; | |||||
| # endif | |||||
| #else | |||||
| /* no way to test, disable to be safe */ | |||||
| info->data.ia32.fxsr = info->data.ia32.sse = info->data.ia32.sse2 = info->data.ia32.sse3 = info->data.ia32.ssse3 = false; | |||||
| #endif | |||||
| #ifdef DEBUG | |||||
| fprintf(stderr, " SSE OS sup . %c\n", info->data.ia32.sse ? 'Y' : 'n'); | |||||
| #endif | |||||
| } | |||||
| } | |||||
| #else | |||||
| info->use_asm = false; | |||||
| #endif | |||||
| /* | |||||
| * PPC-specific | |||||
| */ | |||||
| #elif defined FLAC__CPU_PPC | |||||
| info->type = FLAC__CPUINFO_TYPE_PPC; | |||||
| # if !defined FLAC__NO_ASM | |||||
| info->use_asm = true; | |||||
| # ifdef FLAC__USE_ALTIVEC | |||||
| # if defined FLAC__SYS_DARWIN | |||||
| { | |||||
| int val = 0, mib[2] = { CTL_HW, HW_VECTORUNIT }; | |||||
| size_t len = sizeof(val); | |||||
| info->data.ppc.altivec = !(sysctl(mib, 2, &val, &len, NULL, 0) || !val); | |||||
| } | |||||
| { | |||||
| host_basic_info_data_t hostInfo; | |||||
| mach_msg_type_number_t infoCount; | |||||
| infoCount = HOST_BASIC_INFO_COUNT; | |||||
| host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostInfo, &infoCount); | |||||
| info->data.ppc.ppc64 = (hostInfo.cpu_type == CPU_TYPE_POWERPC) && (hostInfo.cpu_subtype == CPU_SUBTYPE_POWERPC_970); | |||||
| } | |||||
| # else /* FLAC__USE_ALTIVEC && !FLAC__SYS_DARWIN */ | |||||
| { | |||||
| /* no Darwin, do it the brute-force way */ | |||||
| /* @@@@@@ this is not thread-safe; replace with SSE OS method above or remove */ | |||||
| info->data.ppc.altivec = 0; | |||||
| info->data.ppc.ppc64 = 0; | |||||
| signal (SIGILL, sigill_handler); | |||||
| canjump = 0; | |||||
| if (!sigsetjmp (jmpbuf, 1)) { | |||||
| canjump = 1; | |||||
| asm volatile ( | |||||
| "mtspr 256, %0\n\t" | |||||
| "vand %%v0, %%v0, %%v0" | |||||
| : | |||||
| : "r" (-1) | |||||
| ); | |||||
| info->data.ppc.altivec = 1; | |||||
| } | |||||
| canjump = 0; | |||||
| if (!sigsetjmp (jmpbuf, 1)) { | |||||
| int x = 0; | |||||
| canjump = 1; | |||||
| /* PPC64 hardware implements the cntlzd instruction */ | |||||
| asm volatile ("cntlzd %0, %1" : "=r" (x) : "r" (x) ); | |||||
| info->data.ppc.ppc64 = 1; | |||||
| } | |||||
| signal (SIGILL, SIG_DFL); /*@@@@@@ should save and restore old signal */ | |||||
| } | |||||
| # endif | |||||
| # else /* !FLAC__USE_ALTIVEC */ | |||||
| info->data.ppc.altivec = 0; | |||||
| info->data.ppc.ppc64 = 0; | |||||
| # endif | |||||
| # else | |||||
| info->use_asm = false; | |||||
| # endif | |||||
| /* | |||||
| * unknown CPI | |||||
| */ | |||||
| #else | |||||
| info->type = FLAC__CPUINFO_TYPE_UNKNOWN; | |||||
| info->use_asm = false; | |||||
| #endif | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,148 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 "juce_FlacHeader.h" | |||||
| #if JUCE_USE_FLAC | |||||
| #if HAVE_CONFIG_H | |||||
| # include <config.h> | |||||
| #endif | |||||
| #include "include/private/crc.h" | |||||
| /* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */ | |||||
| FLAC__byte const FLAC__crc8_table[256] = { | |||||
| 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, | |||||
| 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, | |||||
| 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, | |||||
| 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, | |||||
| 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, | |||||
| 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, | |||||
| 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, | |||||
| 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, | |||||
| 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, | |||||
| 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, | |||||
| 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, | |||||
| 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, | |||||
| 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, | |||||
| 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, | |||||
| 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, | |||||
| 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, | |||||
| 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, | |||||
| 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, | |||||
| 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, | |||||
| 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, | |||||
| 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, | |||||
| 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, | |||||
| 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, | |||||
| 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, | |||||
| 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, | |||||
| 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, | |||||
| 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, | |||||
| 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, | |||||
| 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, | |||||
| 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, | |||||
| 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, | |||||
| 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 | |||||
| }; | |||||
| /* CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0 */ | |||||
| unsigned FLAC__crc16_table[256] = { | |||||
| 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011, | |||||
| 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022, | |||||
| 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072, | |||||
| 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041, | |||||
| 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2, | |||||
| 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1, | |||||
| 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1, | |||||
| 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082, | |||||
| 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192, | |||||
| 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1, | |||||
| 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1, | |||||
| 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2, | |||||
| 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151, | |||||
| 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162, | |||||
| 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132, | |||||
| 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101, | |||||
| 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312, | |||||
| 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321, | |||||
| 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371, | |||||
| 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342, | |||||
| 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1, | |||||
| 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2, | |||||
| 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2, | |||||
| 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381, | |||||
| 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291, | |||||
| 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2, | |||||
| 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2, | |||||
| 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1, | |||||
| 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252, | |||||
| 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261, | |||||
| 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231, | |||||
| 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202 | |||||
| }; | |||||
| void FLAC__crc8_update(const FLAC__byte data, FLAC__uint8 *crc) | |||||
| { | |||||
| *crc = FLAC__crc8_table[*crc ^ data]; | |||||
| } | |||||
| void FLAC__crc8_update_block(const FLAC__byte *data, unsigned len, FLAC__uint8 *crc) | |||||
| { | |||||
| while(len--) | |||||
| *crc = FLAC__crc8_table[*crc ^ *data++]; | |||||
| } | |||||
| FLAC__uint8 FLAC__crc8(const FLAC__byte *data, unsigned len) | |||||
| { | |||||
| FLAC__uint8 crc = 0; | |||||
| while(len--) | |||||
| crc = FLAC__crc8_table[crc ^ *data++]; | |||||
| return crc; | |||||
| } | |||||
| unsigned FLAC__crc16(const FLAC__byte *data, unsigned len) | |||||
| { | |||||
| unsigned crc = 0; | |||||
| while(len--) | |||||
| crc = ((crc<<8) ^ FLAC__crc16_table[(crc>>8) ^ *data++]) & 0xffff; | |||||
| return crc; | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,441 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 "juce_FlacHeader.h" | |||||
| #if JUCE_USE_FLAC | |||||
| #if HAVE_CONFIG_H | |||||
| # include <config.h> | |||||
| #endif | |||||
| #include <math.h> | |||||
| #include <string.h> | |||||
| #include "include/private/bitmath.h" | |||||
| #include "include/private/fixed.h" | |||||
| #include "../assert.h" | |||||
| #ifndef M_LN2 | |||||
| /* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */ | |||||
| #define M_LN2 0.69314718055994530942 | |||||
| #endif | |||||
| #ifdef min | |||||
| #undef min | |||||
| #endif | |||||
| #define min(x,y) ((x) < (y)? (x) : (y)) | |||||
| #ifdef local_abs | |||||
| #undef local_abs | |||||
| #endif | |||||
| #define local_abs(x) ((unsigned)((x)<0? -(x) : (x))) | |||||
| #ifdef FLAC__INTEGER_ONLY_LIBRARY | |||||
| /* rbps stands for residual bits per sample | |||||
| * | |||||
| * (ln(2) * err) | |||||
| * rbps = log (-----------) | |||||
| * 2 ( n ) | |||||
| */ | |||||
| static FLAC__fixedpoint local__compute_rbps_integerized(FLAC__uint32 err, FLAC__uint32 n) | |||||
| { | |||||
| FLAC__uint32 rbps; | |||||
| unsigned bits; /* the number of bits required to represent a number */ | |||||
| int fracbits; /* the number of bits of rbps that comprise the fractional part */ | |||||
| FLAC__ASSERT(sizeof(rbps) == sizeof(FLAC__fixedpoint)); | |||||
| FLAC__ASSERT(err > 0); | |||||
| FLAC__ASSERT(n > 0); | |||||
| FLAC__ASSERT(n <= FLAC__MAX_BLOCK_SIZE); | |||||
| if(err <= n) | |||||
| return 0; | |||||
| /* | |||||
| * The above two things tell us 1) n fits in 16 bits; 2) err/n > 1. | |||||
| * These allow us later to know we won't lose too much precision in the | |||||
| * fixed-point division (err<<fracbits)/n. | |||||
| */ | |||||
| fracbits = (8*sizeof(err)) - (FLAC__bitmath_ilog2(err)+1); | |||||
| err <<= fracbits; | |||||
| err /= n; | |||||
| /* err now holds err/n with fracbits fractional bits */ | |||||
| /* | |||||
| * Whittle err down to 16 bits max. 16 significant bits is enough for | |||||
| * our purposes. | |||||
| */ | |||||
| FLAC__ASSERT(err > 0); | |||||
| bits = FLAC__bitmath_ilog2(err)+1; | |||||
| if(bits > 16) { | |||||
| err >>= (bits-16); | |||||
| fracbits -= (bits-16); | |||||
| } | |||||
| rbps = (FLAC__uint32)err; | |||||
| /* Multiply by fixed-point version of ln(2), with 16 fractional bits */ | |||||
| rbps *= FLAC__FP_LN2; | |||||
| fracbits += 16; | |||||
| FLAC__ASSERT(fracbits >= 0); | |||||
| /* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */ | |||||
| { | |||||
| const int f = fracbits & 3; | |||||
| if(f) { | |||||
| rbps >>= f; | |||||
| fracbits -= f; | |||||
| } | |||||
| } | |||||
| rbps = FLAC__fixedpoint_log2(rbps, fracbits, (unsigned)(-1)); | |||||
| if(rbps == 0) | |||||
| return 0; | |||||
| /* | |||||
| * The return value must have 16 fractional bits. Since the whole part | |||||
| * of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits | |||||
| * must be >= -3, these assertion allows us to be able to shift rbps | |||||
| * left if necessary to get 16 fracbits without losing any bits of the | |||||
| * whole part of rbps. | |||||
| * | |||||
| * There is a slight chance due to accumulated error that the whole part | |||||
| * will require 6 bits, so we use 6 in the assertion. Really though as | |||||
| * long as it fits in 13 bits (32 - (16 - (-3))) we are fine. | |||||
| */ | |||||
| FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6); | |||||
| FLAC__ASSERT(fracbits >= -3); | |||||
| /* now shift the decimal point into place */ | |||||
| if(fracbits < 16) | |||||
| return rbps << (16-fracbits); | |||||
| else if(fracbits > 16) | |||||
| return rbps >> (fracbits-16); | |||||
| else | |||||
| return rbps; | |||||
| } | |||||
| static FLAC__fixedpoint local__compute_rbps_wide_integerized(FLAC__uint64 err, FLAC__uint32 n) | |||||
| { | |||||
| FLAC__uint32 rbps; | |||||
| unsigned bits; /* the number of bits required to represent a number */ | |||||
| int fracbits; /* the number of bits of rbps that comprise the fractional part */ | |||||
| FLAC__ASSERT(sizeof(rbps) == sizeof(FLAC__fixedpoint)); | |||||
| FLAC__ASSERT(err > 0); | |||||
| FLAC__ASSERT(n > 0); | |||||
| FLAC__ASSERT(n <= FLAC__MAX_BLOCK_SIZE); | |||||
| if(err <= n) | |||||
| return 0; | |||||
| /* | |||||
| * The above two things tell us 1) n fits in 16 bits; 2) err/n > 1. | |||||
| * These allow us later to know we won't lose too much precision in the | |||||
| * fixed-point division (err<<fracbits)/n. | |||||
| */ | |||||
| fracbits = (8*sizeof(err)) - (FLAC__bitmath_ilog2_wide(err)+1); | |||||
| err <<= fracbits; | |||||
| err /= n; | |||||
| /* err now holds err/n with fracbits fractional bits */ | |||||
| /* | |||||
| * Whittle err down to 16 bits max. 16 significant bits is enough for | |||||
| * our purposes. | |||||
| */ | |||||
| FLAC__ASSERT(err > 0); | |||||
| bits = FLAC__bitmath_ilog2_wide(err)+1; | |||||
| if(bits > 16) { | |||||
| err >>= (bits-16); | |||||
| fracbits -= (bits-16); | |||||
| } | |||||
| rbps = (FLAC__uint32)err; | |||||
| /* Multiply by fixed-point version of ln(2), with 16 fractional bits */ | |||||
| rbps *= FLAC__FP_LN2; | |||||
| fracbits += 16; | |||||
| FLAC__ASSERT(fracbits >= 0); | |||||
| /* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */ | |||||
| { | |||||
| const int f = fracbits & 3; | |||||
| if(f) { | |||||
| rbps >>= f; | |||||
| fracbits -= f; | |||||
| } | |||||
| } | |||||
| rbps = FLAC__fixedpoint_log2(rbps, fracbits, (unsigned)(-1)); | |||||
| if(rbps == 0) | |||||
| return 0; | |||||
| /* | |||||
| * The return value must have 16 fractional bits. Since the whole part | |||||
| * of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits | |||||
| * must be >= -3, these assertion allows us to be able to shift rbps | |||||
| * left if necessary to get 16 fracbits without losing any bits of the | |||||
| * whole part of rbps. | |||||
| * | |||||
| * There is a slight chance due to accumulated error that the whole part | |||||
| * will require 6 bits, so we use 6 in the assertion. Really though as | |||||
| * long as it fits in 13 bits (32 - (16 - (-3))) we are fine. | |||||
| */ | |||||
| FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6); | |||||
| FLAC__ASSERT(fracbits >= -3); | |||||
| /* now shift the decimal point into place */ | |||||
| if(fracbits < 16) | |||||
| return rbps << (16-fracbits); | |||||
| else if(fracbits > 16) | |||||
| return rbps >> (fracbits-16); | |||||
| else | |||||
| return rbps; | |||||
| } | |||||
| #endif | |||||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||||
| unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) | |||||
| #else | |||||
| unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) | |||||
| #endif | |||||
| { | |||||
| FLAC__int32 last_error_0 = data[-1]; | |||||
| FLAC__int32 last_error_1 = data[-1] - data[-2]; | |||||
| FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]); | |||||
| FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]); | |||||
| FLAC__int32 error, save; | |||||
| FLAC__uint32 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0; | |||||
| unsigned i, order; | |||||
| for(i = 0; i < data_len; i++) { | |||||
| error = data[i] ; total_error_0 += local_abs(error); save = error; | |||||
| error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error; | |||||
| error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error; | |||||
| error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error; | |||||
| error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save; | |||||
| } | |||||
| if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4)) | |||||
| order = 0; | |||||
| else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4)) | |||||
| order = 1; | |||||
| else if(total_error_2 < min(total_error_3, total_error_4)) | |||||
| order = 2; | |||||
| else if(total_error_3 < total_error_4) | |||||
| order = 3; | |||||
| else | |||||
| order = 4; | |||||
| /* Estimate the expected number of bits per residual signal sample. */ | |||||
| /* 'total_error*' is linearly related to the variance of the residual */ | |||||
| /* signal, so we use it directly to compute E(|x|) */ | |||||
| FLAC__ASSERT(data_len > 0 || total_error_0 == 0); | |||||
| FLAC__ASSERT(data_len > 0 || total_error_1 == 0); | |||||
| FLAC__ASSERT(data_len > 0 || total_error_2 == 0); | |||||
| FLAC__ASSERT(data_len > 0 || total_error_3 == 0); | |||||
| FLAC__ASSERT(data_len > 0 || total_error_4 == 0); | |||||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||||
| residual_bits_per_sample[0] = (FLAC__float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||||
| residual_bits_per_sample[1] = (FLAC__float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||||
| residual_bits_per_sample[2] = (FLAC__float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||||
| residual_bits_per_sample[3] = (FLAC__float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||||
| residual_bits_per_sample[4] = (FLAC__float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||||
| #else | |||||
| residual_bits_per_sample[0] = (total_error_0 > 0) ? local__compute_rbps_integerized(total_error_0, data_len) : 0; | |||||
| residual_bits_per_sample[1] = (total_error_1 > 0) ? local__compute_rbps_integerized(total_error_1, data_len) : 0; | |||||
| residual_bits_per_sample[2] = (total_error_2 > 0) ? local__compute_rbps_integerized(total_error_2, data_len) : 0; | |||||
| residual_bits_per_sample[3] = (total_error_3 > 0) ? local__compute_rbps_integerized(total_error_3, data_len) : 0; | |||||
| residual_bits_per_sample[4] = (total_error_4 > 0) ? local__compute_rbps_integerized(total_error_4, data_len) : 0; | |||||
| #endif | |||||
| return order; | |||||
| } | |||||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||||
| unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) | |||||
| #else | |||||
| unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) | |||||
| #endif | |||||
| { | |||||
| FLAC__int32 last_error_0 = data[-1]; | |||||
| FLAC__int32 last_error_1 = data[-1] - data[-2]; | |||||
| FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]); | |||||
| FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]); | |||||
| FLAC__int32 error, save; | |||||
| /* total_error_* are 64-bits to avoid overflow when encoding | |||||
| * erratic signals when the bits-per-sample and blocksize are | |||||
| * large. | |||||
| */ | |||||
| FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0; | |||||
| unsigned i, order; | |||||
| for(i = 0; i < data_len; i++) { | |||||
| error = data[i] ; total_error_0 += local_abs(error); save = error; | |||||
| error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error; | |||||
| error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error; | |||||
| error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error; | |||||
| error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save; | |||||
| } | |||||
| if(total_error_0 < min(min(min(total_error_1, total_error_2), total_error_3), total_error_4)) | |||||
| order = 0; | |||||
| else if(total_error_1 < min(min(total_error_2, total_error_3), total_error_4)) | |||||
| order = 1; | |||||
| else if(total_error_2 < min(total_error_3, total_error_4)) | |||||
| order = 2; | |||||
| else if(total_error_3 < total_error_4) | |||||
| order = 3; | |||||
| else | |||||
| order = 4; | |||||
| /* Estimate the expected number of bits per residual signal sample. */ | |||||
| /* 'total_error*' is linearly related to the variance of the residual */ | |||||
| /* signal, so we use it directly to compute E(|x|) */ | |||||
| FLAC__ASSERT(data_len > 0 || total_error_0 == 0); | |||||
| FLAC__ASSERT(data_len > 0 || total_error_1 == 0); | |||||
| FLAC__ASSERT(data_len > 0 || total_error_2 == 0); | |||||
| FLAC__ASSERT(data_len > 0 || total_error_3 == 0); | |||||
| FLAC__ASSERT(data_len > 0 || total_error_4 == 0); | |||||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||||
| #if defined _MSC_VER || defined __MINGW32__ | |||||
| /* with MSVC you have to spoon feed it the casting */ | |||||
| residual_bits_per_sample[0] = (FLAC__float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||||
| residual_bits_per_sample[1] = (FLAC__float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||||
| residual_bits_per_sample[2] = (FLAC__float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||||
| residual_bits_per_sample[3] = (FLAC__float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||||
| residual_bits_per_sample[4] = (FLAC__float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)(FLAC__int64)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||||
| #else | |||||
| residual_bits_per_sample[0] = (FLAC__float)((total_error_0 > 0) ? log(M_LN2 * (FLAC__double)total_error_0 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||||
| residual_bits_per_sample[1] = (FLAC__float)((total_error_1 > 0) ? log(M_LN2 * (FLAC__double)total_error_1 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||||
| residual_bits_per_sample[2] = (FLAC__float)((total_error_2 > 0) ? log(M_LN2 * (FLAC__double)total_error_2 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||||
| residual_bits_per_sample[3] = (FLAC__float)((total_error_3 > 0) ? log(M_LN2 * (FLAC__double)total_error_3 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||||
| residual_bits_per_sample[4] = (FLAC__float)((total_error_4 > 0) ? log(M_LN2 * (FLAC__double)total_error_4 / (FLAC__double)data_len) / M_LN2 : 0.0); | |||||
| #endif | |||||
| #else | |||||
| residual_bits_per_sample[0] = (total_error_0 > 0) ? local__compute_rbps_wide_integerized(total_error_0, data_len) : 0; | |||||
| residual_bits_per_sample[1] = (total_error_1 > 0) ? local__compute_rbps_wide_integerized(total_error_1, data_len) : 0; | |||||
| residual_bits_per_sample[2] = (total_error_2 > 0) ? local__compute_rbps_wide_integerized(total_error_2, data_len) : 0; | |||||
| residual_bits_per_sample[3] = (total_error_3 > 0) ? local__compute_rbps_wide_integerized(total_error_3, data_len) : 0; | |||||
| residual_bits_per_sample[4] = (total_error_4 > 0) ? local__compute_rbps_wide_integerized(total_error_4, data_len) : 0; | |||||
| #endif | |||||
| return order; | |||||
| } | |||||
| void FLAC__fixed_compute_residual(const FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__int32 residual[]) | |||||
| { | |||||
| const int idata_len = (int)data_len; | |||||
| int i; | |||||
| switch(order) { | |||||
| case 0: | |||||
| FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0])); | |||||
| memcpy(residual, data, sizeof(residual[0])*data_len); | |||||
| break; | |||||
| case 1: | |||||
| for(i = 0; i < idata_len; i++) | |||||
| residual[i] = data[i] - data[i-1]; | |||||
| break; | |||||
| case 2: | |||||
| for(i = 0; i < idata_len; i++) | |||||
| #if 1 /* OPT: may be faster with some compilers on some systems */ | |||||
| residual[i] = data[i] - (data[i-1] << 1) + data[i-2]; | |||||
| #else | |||||
| residual[i] = data[i] - 2*data[i-1] + data[i-2]; | |||||
| #endif | |||||
| break; | |||||
| case 3: | |||||
| for(i = 0; i < idata_len; i++) | |||||
| #if 1 /* OPT: may be faster with some compilers on some systems */ | |||||
| residual[i] = data[i] - (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) - data[i-3]; | |||||
| #else | |||||
| residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3]; | |||||
| #endif | |||||
| break; | |||||
| case 4: | |||||
| for(i = 0; i < idata_len; i++) | |||||
| #if 1 /* OPT: may be faster with some compilers on some systems */ | |||||
| residual[i] = data[i] - ((data[i-1]+data[i-3])<<2) + ((data[i-2]<<2) + (data[i-2]<<1)) + data[i-4]; | |||||
| #else | |||||
| residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4]; | |||||
| #endif | |||||
| break; | |||||
| default: | |||||
| FLAC__ASSERT(0); | |||||
| } | |||||
| } | |||||
| void FLAC__fixed_restore_signal(const FLAC__int32 residual[], unsigned data_len, unsigned order, FLAC__int32 data[]) | |||||
| { | |||||
| int i, idata_len = (int)data_len; | |||||
| switch(order) { | |||||
| case 0: | |||||
| FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0])); | |||||
| memcpy(data, residual, sizeof(residual[0])*data_len); | |||||
| break; | |||||
| case 1: | |||||
| for(i = 0; i < idata_len; i++) | |||||
| data[i] = residual[i] + data[i-1]; | |||||
| break; | |||||
| case 2: | |||||
| for(i = 0; i < idata_len; i++) | |||||
| #if 1 /* OPT: may be faster with some compilers on some systems */ | |||||
| data[i] = residual[i] + (data[i-1]<<1) - data[i-2]; | |||||
| #else | |||||
| data[i] = residual[i] + 2*data[i-1] - data[i-2]; | |||||
| #endif | |||||
| break; | |||||
| case 3: | |||||
| for(i = 0; i < idata_len; i++) | |||||
| #if 1 /* OPT: may be faster with some compilers on some systems */ | |||||
| data[i] = residual[i] + (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) + data[i-3]; | |||||
| #else | |||||
| data[i] = residual[i] + 3*data[i-1] - 3*data[i-2] + data[i-3]; | |||||
| #endif | |||||
| break; | |||||
| case 4: | |||||
| for(i = 0; i < idata_len; i++) | |||||
| #if 1 /* OPT: may be faster with some compilers on some systems */ | |||||
| data[i] = residual[i] + ((data[i-1]+data[i-3])<<2) - ((data[i-2]<<2) + (data[i-2]<<1)) - data[i-4]; | |||||
| #else | |||||
| data[i] = residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4]; | |||||
| #endif | |||||
| break; | |||||
| default: | |||||
| FLAC__ASSERT(0); | |||||
| } | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,314 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 "juce_FlacHeader.h" | |||||
| #if JUCE_USE_FLAC | |||||
| #if HAVE_CONFIG_H | |||||
| # include <config.h> | |||||
| #endif | |||||
| #include "../assert.h" | |||||
| #include "include/private/float.h" | |||||
| #ifdef FLAC__INTEGER_ONLY_LIBRARY | |||||
| /* adjust for compilers that can't understand using LLU suffix for uint64_t literals */ | |||||
| #ifdef _MSC_VER | |||||
| #define FLAC__U64L(x) x | |||||
| #else | |||||
| #define FLAC__U64L(x) x##LLU | |||||
| #endif | |||||
| const FLAC__fixedpoint FLAC__FP_ZERO = 0; | |||||
| const FLAC__fixedpoint FLAC__FP_ONE_HALF = 0x00008000; | |||||
| const FLAC__fixedpoint FLAC__FP_ONE = 0x00010000; | |||||
| const FLAC__fixedpoint FLAC__FP_LN2 = 45426; | |||||
| const FLAC__fixedpoint FLAC__FP_E = 178145; | |||||
| /* Lookup tables for Knuth's logarithm algorithm */ | |||||
| #define LOG2_LOOKUP_PRECISION 16 | |||||
| static const FLAC__uint32 log2_lookup[][LOG2_LOOKUP_PRECISION] = { | |||||
| { | |||||
| /* | |||||
| * 0 fraction bits | |||||
| */ | |||||
| /* undefined */ 0x00000000, | |||||
| /* lg(2/1) = */ 0x00000001, | |||||
| /* lg(4/3) = */ 0x00000000, | |||||
| /* lg(8/7) = */ 0x00000000, | |||||
| /* lg(16/15) = */ 0x00000000, | |||||
| /* lg(32/31) = */ 0x00000000, | |||||
| /* lg(64/63) = */ 0x00000000, | |||||
| /* lg(128/127) = */ 0x00000000, | |||||
| /* lg(256/255) = */ 0x00000000, | |||||
| /* lg(512/511) = */ 0x00000000, | |||||
| /* lg(1024/1023) = */ 0x00000000, | |||||
| /* lg(2048/2047) = */ 0x00000000, | |||||
| /* lg(4096/4095) = */ 0x00000000, | |||||
| /* lg(8192/8191) = */ 0x00000000, | |||||
| /* lg(16384/16383) = */ 0x00000000, | |||||
| /* lg(32768/32767) = */ 0x00000000 | |||||
| }, | |||||
| { | |||||
| /* | |||||
| * 4 fraction bits | |||||
| */ | |||||
| /* undefined */ 0x00000000, | |||||
| /* lg(2/1) = */ 0x00000010, | |||||
| /* lg(4/3) = */ 0x00000007, | |||||
| /* lg(8/7) = */ 0x00000003, | |||||
| /* lg(16/15) = */ 0x00000001, | |||||
| /* lg(32/31) = */ 0x00000001, | |||||
| /* lg(64/63) = */ 0x00000000, | |||||
| /* lg(128/127) = */ 0x00000000, | |||||
| /* lg(256/255) = */ 0x00000000, | |||||
| /* lg(512/511) = */ 0x00000000, | |||||
| /* lg(1024/1023) = */ 0x00000000, | |||||
| /* lg(2048/2047) = */ 0x00000000, | |||||
| /* lg(4096/4095) = */ 0x00000000, | |||||
| /* lg(8192/8191) = */ 0x00000000, | |||||
| /* lg(16384/16383) = */ 0x00000000, | |||||
| /* lg(32768/32767) = */ 0x00000000 | |||||
| }, | |||||
| { | |||||
| /* | |||||
| * 8 fraction bits | |||||
| */ | |||||
| /* undefined */ 0x00000000, | |||||
| /* lg(2/1) = */ 0x00000100, | |||||
| /* lg(4/3) = */ 0x0000006a, | |||||
| /* lg(8/7) = */ 0x00000031, | |||||
| /* lg(16/15) = */ 0x00000018, | |||||
| /* lg(32/31) = */ 0x0000000c, | |||||
| /* lg(64/63) = */ 0x00000006, | |||||
| /* lg(128/127) = */ 0x00000003, | |||||
| /* lg(256/255) = */ 0x00000001, | |||||
| /* lg(512/511) = */ 0x00000001, | |||||
| /* lg(1024/1023) = */ 0x00000000, | |||||
| /* lg(2048/2047) = */ 0x00000000, | |||||
| /* lg(4096/4095) = */ 0x00000000, | |||||
| /* lg(8192/8191) = */ 0x00000000, | |||||
| /* lg(16384/16383) = */ 0x00000000, | |||||
| /* lg(32768/32767) = */ 0x00000000 | |||||
| }, | |||||
| { | |||||
| /* | |||||
| * 12 fraction bits | |||||
| */ | |||||
| /* undefined */ 0x00000000, | |||||
| /* lg(2/1) = */ 0x00001000, | |||||
| /* lg(4/3) = */ 0x000006a4, | |||||
| /* lg(8/7) = */ 0x00000315, | |||||
| /* lg(16/15) = */ 0x0000017d, | |||||
| /* lg(32/31) = */ 0x000000bc, | |||||
| /* lg(64/63) = */ 0x0000005d, | |||||
| /* lg(128/127) = */ 0x0000002e, | |||||
| /* lg(256/255) = */ 0x00000017, | |||||
| /* lg(512/511) = */ 0x0000000c, | |||||
| /* lg(1024/1023) = */ 0x00000006, | |||||
| /* lg(2048/2047) = */ 0x00000003, | |||||
| /* lg(4096/4095) = */ 0x00000001, | |||||
| /* lg(8192/8191) = */ 0x00000001, | |||||
| /* lg(16384/16383) = */ 0x00000000, | |||||
| /* lg(32768/32767) = */ 0x00000000 | |||||
| }, | |||||
| { | |||||
| /* | |||||
| * 16 fraction bits | |||||
| */ | |||||
| /* undefined */ 0x00000000, | |||||
| /* lg(2/1) = */ 0x00010000, | |||||
| /* lg(4/3) = */ 0x00006a40, | |||||
| /* lg(8/7) = */ 0x00003151, | |||||
| /* lg(16/15) = */ 0x000017d6, | |||||
| /* lg(32/31) = */ 0x00000bba, | |||||
| /* lg(64/63) = */ 0x000005d1, | |||||
| /* lg(128/127) = */ 0x000002e6, | |||||
| /* lg(256/255) = */ 0x00000172, | |||||
| /* lg(512/511) = */ 0x000000b9, | |||||
| /* lg(1024/1023) = */ 0x0000005c, | |||||
| /* lg(2048/2047) = */ 0x0000002e, | |||||
| /* lg(4096/4095) = */ 0x00000017, | |||||
| /* lg(8192/8191) = */ 0x0000000c, | |||||
| /* lg(16384/16383) = */ 0x00000006, | |||||
| /* lg(32768/32767) = */ 0x00000003 | |||||
| }, | |||||
| { | |||||
| /* | |||||
| * 20 fraction bits | |||||
| */ | |||||
| /* undefined */ 0x00000000, | |||||
| /* lg(2/1) = */ 0x00100000, | |||||
| /* lg(4/3) = */ 0x0006a3fe, | |||||
| /* lg(8/7) = */ 0x00031513, | |||||
| /* lg(16/15) = */ 0x00017d60, | |||||
| /* lg(32/31) = */ 0x0000bb9d, | |||||
| /* lg(64/63) = */ 0x00005d10, | |||||
| /* lg(128/127) = */ 0x00002e59, | |||||
| /* lg(256/255) = */ 0x00001721, | |||||
| /* lg(512/511) = */ 0x00000b8e, | |||||
| /* lg(1024/1023) = */ 0x000005c6, | |||||
| /* lg(2048/2047) = */ 0x000002e3, | |||||
| /* lg(4096/4095) = */ 0x00000171, | |||||
| /* lg(8192/8191) = */ 0x000000b9, | |||||
| /* lg(16384/16383) = */ 0x0000005c, | |||||
| /* lg(32768/32767) = */ 0x0000002e | |||||
| }, | |||||
| { | |||||
| /* | |||||
| * 24 fraction bits | |||||
| */ | |||||
| /* undefined */ 0x00000000, | |||||
| /* lg(2/1) = */ 0x01000000, | |||||
| /* lg(4/3) = */ 0x006a3fe6, | |||||
| /* lg(8/7) = */ 0x00315130, | |||||
| /* lg(16/15) = */ 0x0017d605, | |||||
| /* lg(32/31) = */ 0x000bb9ca, | |||||
| /* lg(64/63) = */ 0x0005d0fc, | |||||
| /* lg(128/127) = */ 0x0002e58f, | |||||
| /* lg(256/255) = */ 0x0001720e, | |||||
| /* lg(512/511) = */ 0x0000b8d8, | |||||
| /* lg(1024/1023) = */ 0x00005c61, | |||||
| /* lg(2048/2047) = */ 0x00002e2d, | |||||
| /* lg(4096/4095) = */ 0x00001716, | |||||
| /* lg(8192/8191) = */ 0x00000b8b, | |||||
| /* lg(16384/16383) = */ 0x000005c5, | |||||
| /* lg(32768/32767) = */ 0x000002e3 | |||||
| }, | |||||
| { | |||||
| /* | |||||
| * 28 fraction bits | |||||
| */ | |||||
| /* undefined */ 0x00000000, | |||||
| /* lg(2/1) = */ 0x10000000, | |||||
| /* lg(4/3) = */ 0x06a3fe5c, | |||||
| /* lg(8/7) = */ 0x03151301, | |||||
| /* lg(16/15) = */ 0x017d6049, | |||||
| /* lg(32/31) = */ 0x00bb9ca6, | |||||
| /* lg(64/63) = */ 0x005d0fba, | |||||
| /* lg(128/127) = */ 0x002e58f7, | |||||
| /* lg(256/255) = */ 0x001720da, | |||||
| /* lg(512/511) = */ 0x000b8d87, | |||||
| /* lg(1024/1023) = */ 0x0005c60b, | |||||
| /* lg(2048/2047) = */ 0x0002e2d7, | |||||
| /* lg(4096/4095) = */ 0x00017160, | |||||
| /* lg(8192/8191) = */ 0x0000b8ad, | |||||
| /* lg(16384/16383) = */ 0x00005c56, | |||||
| /* lg(32768/32767) = */ 0x00002e2b | |||||
| } | |||||
| }; | |||||
| #if 0 | |||||
| static const FLAC__uint64 log2_lookup_wide[] = { | |||||
| { | |||||
| /* | |||||
| * 32 fraction bits | |||||
| */ | |||||
| /* undefined */ 0x00000000, | |||||
| /* lg(2/1) = */ FLAC__U64L(0x100000000), | |||||
| /* lg(4/3) = */ FLAC__U64L(0x6a3fe5c6), | |||||
| /* lg(8/7) = */ FLAC__U64L(0x31513015), | |||||
| /* lg(16/15) = */ FLAC__U64L(0x17d60497), | |||||
| /* lg(32/31) = */ FLAC__U64L(0x0bb9ca65), | |||||
| /* lg(64/63) = */ FLAC__U64L(0x05d0fba2), | |||||
| /* lg(128/127) = */ FLAC__U64L(0x02e58f74), | |||||
| /* lg(256/255) = */ FLAC__U64L(0x01720d9c), | |||||
| /* lg(512/511) = */ FLAC__U64L(0x00b8d875), | |||||
| /* lg(1024/1023) = */ FLAC__U64L(0x005c60aa), | |||||
| /* lg(2048/2047) = */ FLAC__U64L(0x002e2d72), | |||||
| /* lg(4096/4095) = */ FLAC__U64L(0x00171600), | |||||
| /* lg(8192/8191) = */ FLAC__U64L(0x000b8ad2), | |||||
| /* lg(16384/16383) = */ FLAC__U64L(0x0005c55d), | |||||
| /* lg(32768/32767) = */ FLAC__U64L(0x0002e2ac) | |||||
| }, | |||||
| { | |||||
| /* | |||||
| * 48 fraction bits | |||||
| */ | |||||
| /* undefined */ 0x00000000, | |||||
| /* lg(2/1) = */ FLAC__U64L(0x1000000000000), | |||||
| /* lg(4/3) = */ FLAC__U64L(0x6a3fe5c60429), | |||||
| /* lg(8/7) = */ FLAC__U64L(0x315130157f7a), | |||||
| /* lg(16/15) = */ FLAC__U64L(0x17d60496cfbb), | |||||
| /* lg(32/31) = */ FLAC__U64L(0xbb9ca64ecac), | |||||
| /* lg(64/63) = */ FLAC__U64L(0x5d0fba187cd), | |||||
| /* lg(128/127) = */ FLAC__U64L(0x2e58f7441ee), | |||||
| /* lg(256/255) = */ FLAC__U64L(0x1720d9c06a8), | |||||
| /* lg(512/511) = */ FLAC__U64L(0xb8d8752173), | |||||
| /* lg(1024/1023) = */ FLAC__U64L(0x5c60aa252e), | |||||
| /* lg(2048/2047) = */ FLAC__U64L(0x2e2d71b0d8), | |||||
| /* lg(4096/4095) = */ FLAC__U64L(0x1716001719), | |||||
| /* lg(8192/8191) = */ FLAC__U64L(0xb8ad1de1b), | |||||
| /* lg(16384/16383) = */ FLAC__U64L(0x5c55d640d), | |||||
| /* lg(32768/32767) = */ FLAC__U64L(0x2e2abcf52) | |||||
| } | |||||
| }; | |||||
| #endif | |||||
| FLAC__uint32 FLAC__fixedpoint_log2(FLAC__uint32 x, unsigned fracbits, unsigned precision) | |||||
| { | |||||
| const FLAC__uint32 ONE = (1u << fracbits); | |||||
| const FLAC__uint32 *table = log2_lookup[fracbits >> 2]; | |||||
| FLAC__ASSERT(fracbits < 32); | |||||
| FLAC__ASSERT((fracbits & 0x3) == 0); | |||||
| if(x < ONE) | |||||
| return 0; | |||||
| if(precision > LOG2_LOOKUP_PRECISION) | |||||
| precision = LOG2_LOOKUP_PRECISION; | |||||
| /* Knuth's algorithm for computing logarithms, optimized for base-2 with lookup tables */ | |||||
| { | |||||
| FLAC__uint32 y = 0; | |||||
| FLAC__uint32 z = x >> 1, k = 1; | |||||
| while (x > ONE && k < precision) { | |||||
| if (x - z >= ONE) { | |||||
| x -= z; | |||||
| z = x >> k; | |||||
| y += table[k]; | |||||
| } | |||||
| else { | |||||
| z >>= 1; | |||||
| k++; | |||||
| } | |||||
| } | |||||
| return y; | |||||
| } | |||||
| } | |||||
| #endif /* defined FLAC__INTEGER_ONLY_LIBRARY */ | |||||
| #endif | |||||
| @@ -0,0 +1,604 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 "juce_FlacHeader.h" | |||||
| #if JUCE_USE_FLAC | |||||
| #if HAVE_CONFIG_H | |||||
| # include <config.h> | |||||
| #endif | |||||
| #include <stdio.h> | |||||
| #include <stdlib.h> /* for qsort() */ | |||||
| #include <string.h> /* for memset() */ | |||||
| #include "../assert.h" | |||||
| #include "../format.h" | |||||
| #include "include/private/format.h" | |||||
| #ifndef FLaC__INLINE | |||||
| #define FLaC__INLINE | |||||
| #endif | |||||
| #ifdef min | |||||
| #undef min | |||||
| #endif | |||||
| #define min(a,b) ((a)<(b)?(a):(b)) | |||||
| /* adjust for compilers that can't understand using LLU suffix for uint64_t literals */ | |||||
| #ifdef _MSC_VER | |||||
| #define FLAC__U64L(x) x | |||||
| #else | |||||
| #define FLAC__U64L(x) x##LLU | |||||
| #endif | |||||
| /* VERSION should come from configure */ | |||||
| FLAC_API const char *FLAC__VERSION_STRING = VERSION | |||||
| ; | |||||
| #if defined _MSC_VER || defined __BORLANDC__ || defined __MINW32__ | |||||
| /* yet one more hack because of MSVC6: */ | |||||
| FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC 1.2.1 20070917"; | |||||
| #else | |||||
| FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " VERSION " 20070917"; | |||||
| #endif | |||||
| FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' }; | |||||
| FLAC_API const unsigned FLAC__STREAM_SYNC = 0x664C6143; | |||||
| FLAC_API const unsigned FLAC__STREAM_SYNC_LEN = 32; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_APPLICATION_ID_LEN = 32; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */ | |||||
| FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER = FLAC__U64L(0xffffffffffffffff); | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN = 32; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN = 32; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN = 64; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN = 8; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN = 3*8; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN = 64; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN = 8; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN = 12*8; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN = 1; /* bit */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN = 1; /* bit */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN = 6+13*8; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN = 8; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN = 128*8; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN = 64; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN = 1; /* bit */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN = 7+258*8; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_TYPE_LEN = 32; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN = 32; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN = 32; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN = 32; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN = 32; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN = 32; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_COLORS_LEN = 32; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN = 32; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */ | |||||
| FLAC_API const unsigned FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */ | |||||
| FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC = 0x3ffe; | |||||
| FLAC_API const unsigned FLAC__FRAME_HEADER_SYNC_LEN = 14; /* bits */ | |||||
| FLAC_API const unsigned FLAC__FRAME_HEADER_RESERVED_LEN = 1; /* bits */ | |||||
| FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN = 1; /* bits */ | |||||
| FLAC_API const unsigned FLAC__FRAME_HEADER_BLOCK_SIZE_LEN = 4; /* bits */ | |||||
| FLAC_API const unsigned FLAC__FRAME_HEADER_SAMPLE_RATE_LEN = 4; /* bits */ | |||||
| FLAC_API const unsigned FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN = 4; /* bits */ | |||||
| FLAC_API const unsigned FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */ | |||||
| FLAC_API const unsigned FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */ | |||||
| FLAC_API const unsigned FLAC__FRAME_HEADER_CRC_LEN = 8; /* bits */ | |||||
| FLAC_API const unsigned FLAC__FRAME_FOOTER_CRC_LEN = 16; /* bits */ | |||||
| FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */ | |||||
| FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */ | |||||
| FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */ | |||||
| FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN = 5; /* bits */ | |||||
| FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN = 5; /* bits */ | |||||
| FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER = 15; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN)-1 */ | |||||
| FLAC_API const unsigned FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER = 31; /* == (1<<FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN)-1 */ | |||||
| FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[] = { | |||||
| "PARTITIONED_RICE", | |||||
| "PARTITIONED_RICE2" | |||||
| }; | |||||
| FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN = 4; /* bits */ | |||||
| FLAC_API const unsigned FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN = 5; /* bits */ | |||||
| FLAC_API const unsigned FLAC__SUBFRAME_ZERO_PAD_LEN = 1; /* bits */ | |||||
| FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LEN = 6; /* bits */ | |||||
| FLAC_API const unsigned FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN = 1; /* bits */ | |||||
| FLAC_API const unsigned FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK = 0x00; | |||||
| FLAC_API const unsigned FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK = 0x02; | |||||
| FLAC_API const unsigned FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK = 0x10; | |||||
| FLAC_API const unsigned FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK = 0x40; | |||||
| FLAC_API const char * const FLAC__SubframeTypeString[] = { | |||||
| "CONSTANT", | |||||
| "VERBATIM", | |||||
| "FIXED", | |||||
| "LPC" | |||||
| }; | |||||
| FLAC_API const char * const FLAC__ChannelAssignmentString[] = { | |||||
| "INDEPENDENT", | |||||
| "LEFT_SIDE", | |||||
| "RIGHT_SIDE", | |||||
| "MID_SIDE" | |||||
| }; | |||||
| FLAC_API const char * const FLAC__FrameNumberTypeString[] = { | |||||
| "FRAME_NUMBER_TYPE_FRAME_NUMBER", | |||||
| "FRAME_NUMBER_TYPE_SAMPLE_NUMBER" | |||||
| }; | |||||
| FLAC_API const char * const FLAC__MetadataTypeString[] = { | |||||
| "STREAMINFO", | |||||
| "PADDING", | |||||
| "APPLICATION", | |||||
| "SEEKTABLE", | |||||
| "VORBIS_COMMENT", | |||||
| "CUESHEET", | |||||
| "PICTURE" | |||||
| }; | |||||
| FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[] = { | |||||
| "Other", | |||||
| "32x32 pixels 'file icon' (PNG only)", | |||||
| "Other file icon", | |||||
| "Cover (front)", | |||||
| "Cover (back)", | |||||
| "Leaflet page", | |||||
| "Media (e.g. label side of CD)", | |||||
| "Lead artist/lead performer/soloist", | |||||
| "Artist/performer", | |||||
| "Conductor", | |||||
| "Band/Orchestra", | |||||
| "Composer", | |||||
| "Lyricist/text writer", | |||||
| "Recording Location", | |||||
| "During recording", | |||||
| "During performance", | |||||
| "Movie/video screen capture", | |||||
| "A bright coloured fish", | |||||
| "Illustration", | |||||
| "Band/artist logotype", | |||||
| "Publisher/Studio logotype" | |||||
| }; | |||||
| FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(unsigned sample_rate) | |||||
| { | |||||
| if(sample_rate == 0 || sample_rate > FLAC__MAX_SAMPLE_RATE) { | |||||
| return false; | |||||
| } | |||||
| else | |||||
| return true; | |||||
| } | |||||
| FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(unsigned sample_rate) | |||||
| { | |||||
| if( | |||||
| !FLAC__format_sample_rate_is_valid(sample_rate) || | |||||
| ( | |||||
| sample_rate >= (1u << 16) && | |||||
| !(sample_rate % 1000 == 0 || sample_rate % 10 == 0) | |||||
| ) | |||||
| ) { | |||||
| return false; | |||||
| } | |||||
| else | |||||
| return true; | |||||
| } | |||||
| /* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ | |||||
| FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table) | |||||
| { | |||||
| unsigned i; | |||||
| FLAC__uint64 prev_sample_number = 0; | |||||
| FLAC__bool got_prev = false; | |||||
| FLAC__ASSERT(0 != seek_table); | |||||
| for(i = 0; i < seek_table->num_points; i++) { | |||||
| if(got_prev) { | |||||
| if( | |||||
| seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && | |||||
| seek_table->points[i].sample_number <= prev_sample_number | |||||
| ) | |||||
| return false; | |||||
| } | |||||
| prev_sample_number = seek_table->points[i].sample_number; | |||||
| got_prev = true; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| /* used as the sort predicate for qsort() */ | |||||
| static int seekpoint_compare_(const FLAC__StreamMetadata_SeekPoint *l, const FLAC__StreamMetadata_SeekPoint *r) | |||||
| { | |||||
| /* we don't just 'return l->sample_number - r->sample_number' since the result (FLAC__int64) might overflow an 'int' */ | |||||
| if(l->sample_number == r->sample_number) | |||||
| return 0; | |||||
| else if(l->sample_number < r->sample_number) | |||||
| return -1; | |||||
| else | |||||
| return 1; | |||||
| } | |||||
| /* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ | |||||
| FLAC_API unsigned FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table) | |||||
| { | |||||
| unsigned i, j; | |||||
| FLAC__bool first; | |||||
| FLAC__ASSERT(0 != seek_table); | |||||
| /* sort the seekpoints */ | |||||
| qsort(seek_table->points, seek_table->num_points, sizeof(FLAC__StreamMetadata_SeekPoint), (int (*)(const void *, const void *))seekpoint_compare_); | |||||
| /* uniquify the seekpoints */ | |||||
| first = true; | |||||
| for(i = j = 0; i < seek_table->num_points; i++) { | |||||
| if(seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) { | |||||
| if(!first) { | |||||
| if(seek_table->points[i].sample_number == seek_table->points[j-1].sample_number) | |||||
| continue; | |||||
| } | |||||
| } | |||||
| first = false; | |||||
| seek_table->points[j++] = seek_table->points[i]; | |||||
| } | |||||
| for(i = j; i < seek_table->num_points; i++) { | |||||
| seek_table->points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; | |||||
| seek_table->points[i].stream_offset = 0; | |||||
| seek_table->points[i].frame_samples = 0; | |||||
| } | |||||
| return j; | |||||
| } | |||||
| /* | |||||
| * also disallows non-shortest-form encodings, c.f. | |||||
| * http://www.unicode.org/versions/corrigendum1.html | |||||
| * and a more clear explanation at the end of this section: | |||||
| * http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 | |||||
| */ | |||||
| static FLaC__INLINE unsigned utf8len_(const FLAC__byte *utf8) | |||||
| { | |||||
| FLAC__ASSERT(0 != utf8); | |||||
| if ((utf8[0] & 0x80) == 0) { | |||||
| return 1; | |||||
| } | |||||
| else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80) { | |||||
| if ((utf8[0] & 0xFE) == 0xC0) /* overlong sequence check */ | |||||
| return 0; | |||||
| return 2; | |||||
| } | |||||
| else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80) { | |||||
| if (utf8[0] == 0xE0 && (utf8[1] & 0xE0) == 0x80) /* overlong sequence check */ | |||||
| return 0; | |||||
| /* illegal surrogates check (U+D800...U+DFFF and U+FFFE...U+FFFF) */ | |||||
| if (utf8[0] == 0xED && (utf8[1] & 0xE0) == 0xA0) /* D800-DFFF */ | |||||
| return 0; | |||||
| if (utf8[0] == 0xEF && utf8[1] == 0xBF && (utf8[2] & 0xFE) == 0xBE) /* FFFE-FFFF */ | |||||
| return 0; | |||||
| return 3; | |||||
| } | |||||
| else if ((utf8[0] & 0xF8) == 0xF0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80) { | |||||
| if (utf8[0] == 0xF0 && (utf8[1] & 0xF0) == 0x80) /* overlong sequence check */ | |||||
| return 0; | |||||
| return 4; | |||||
| } | |||||
| else if ((utf8[0] & 0xFC) == 0xF8 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80) { | |||||
| if (utf8[0] == 0xF8 && (utf8[1] & 0xF8) == 0x80) /* overlong sequence check */ | |||||
| return 0; | |||||
| return 5; | |||||
| } | |||||
| else if ((utf8[0] & 0xFE) == 0xFC && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80 && (utf8[5] & 0xC0) == 0x80) { | |||||
| if (utf8[0] == 0xFC && (utf8[1] & 0xFC) == 0x80) /* overlong sequence check */ | |||||
| return 0; | |||||
| return 6; | |||||
| } | |||||
| else { | |||||
| return 0; | |||||
| } | |||||
| } | |||||
| FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name) | |||||
| { | |||||
| char c; | |||||
| for(c = *name; c; c = *(++name)) | |||||
| if(c < 0x20 || c == 0x3d || c > 0x7d) | |||||
| return false; | |||||
| return true; | |||||
| } | |||||
| FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, unsigned length) | |||||
| { | |||||
| if(length == (unsigned)(-1)) { | |||||
| while(*value) { | |||||
| unsigned n = utf8len_(value); | |||||
| if(n == 0) | |||||
| return false; | |||||
| value += n; | |||||
| } | |||||
| } | |||||
| else { | |||||
| const FLAC__byte *end = value + length; | |||||
| while(value < end) { | |||||
| unsigned n = utf8len_(value); | |||||
| if(n == 0) | |||||
| return false; | |||||
| value += n; | |||||
| } | |||||
| if(value != end) | |||||
| return false; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, unsigned length) | |||||
| { | |||||
| const FLAC__byte *s, *end; | |||||
| for(s = entry, end = s + length; s < end && *s != '='; s++) { | |||||
| if(*s < 0x20 || *s > 0x7D) | |||||
| return false; | |||||
| } | |||||
| if(s == end) | |||||
| return false; | |||||
| s++; /* skip '=' */ | |||||
| while(s < end) { | |||||
| unsigned n = utf8len_(s); | |||||
| if(n == 0) | |||||
| return false; | |||||
| s += n; | |||||
| } | |||||
| if(s != end) | |||||
| return false; | |||||
| return true; | |||||
| } | |||||
| /* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ | |||||
| FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation) | |||||
| { | |||||
| unsigned i, j; | |||||
| if(check_cd_da_subset) { | |||||
| if(cue_sheet->lead_in < 2 * 44100) { | |||||
| if(violation) *violation = "CD-DA cue sheet must have a lead-in length of at least 2 seconds"; | |||||
| return false; | |||||
| } | |||||
| if(cue_sheet->lead_in % 588 != 0) { | |||||
| if(violation) *violation = "CD-DA cue sheet lead-in length must be evenly divisible by 588 samples"; | |||||
| return false; | |||||
| } | |||||
| } | |||||
| if(cue_sheet->num_tracks == 0) { | |||||
| if(violation) *violation = "cue sheet must have at least one track (the lead-out)"; | |||||
| return false; | |||||
| } | |||||
| if(check_cd_da_subset && cue_sheet->tracks[cue_sheet->num_tracks-1].number != 170) { | |||||
| if(violation) *violation = "CD-DA cue sheet must have a lead-out track number 170 (0xAA)"; | |||||
| return false; | |||||
| } | |||||
| for(i = 0; i < cue_sheet->num_tracks; i++) { | |||||
| if(cue_sheet->tracks[i].number == 0) { | |||||
| if(violation) *violation = "cue sheet may not have a track number 0"; | |||||
| return false; | |||||
| } | |||||
| if(check_cd_da_subset) { | |||||
| if(!((cue_sheet->tracks[i].number >= 1 && cue_sheet->tracks[i].number <= 99) || cue_sheet->tracks[i].number == 170)) { | |||||
| if(violation) *violation = "CD-DA cue sheet track number must be 1-99 or 170"; | |||||
| return false; | |||||
| } | |||||
| } | |||||
| if(check_cd_da_subset && cue_sheet->tracks[i].offset % 588 != 0) { | |||||
| if(violation) { | |||||
| if(i == cue_sheet->num_tracks-1) /* the lead-out track... */ | |||||
| *violation = "CD-DA cue sheet lead-out offset must be evenly divisible by 588 samples"; | |||||
| else | |||||
| *violation = "CD-DA cue sheet track offset must be evenly divisible by 588 samples"; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| if(i < cue_sheet->num_tracks - 1) { | |||||
| if(cue_sheet->tracks[i].num_indices == 0) { | |||||
| if(violation) *violation = "cue sheet track must have at least one index point"; | |||||
| return false; | |||||
| } | |||||
| if(cue_sheet->tracks[i].indices[0].number > 1) { | |||||
| if(violation) *violation = "cue sheet track's first index number must be 0 or 1"; | |||||
| return false; | |||||
| } | |||||
| } | |||||
| for(j = 0; j < cue_sheet->tracks[i].num_indices; j++) { | |||||
| if(check_cd_da_subset && cue_sheet->tracks[i].indices[j].offset % 588 != 0) { | |||||
| if(violation) *violation = "CD-DA cue sheet track index offset must be evenly divisible by 588 samples"; | |||||
| return false; | |||||
| } | |||||
| if(j > 0) { | |||||
| if(cue_sheet->tracks[i].indices[j].number != cue_sheet->tracks[i].indices[j-1].number + 1) { | |||||
| if(violation) *violation = "cue sheet track index numbers must increase by 1"; | |||||
| return false; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| return true; | |||||
| } | |||||
| /* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ | |||||
| FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation) | |||||
| { | |||||
| char *p; | |||||
| FLAC__byte *b; | |||||
| for(p = picture->mime_type; *p; p++) { | |||||
| if(*p < 0x20 || *p > 0x7e) { | |||||
| if(violation) *violation = "MIME type string must contain only printable ASCII characters (0x20-0x7e)"; | |||||
| return false; | |||||
| } | |||||
| } | |||||
| for(b = picture->description; *b; ) { | |||||
| unsigned n = utf8len_(b); | |||||
| if(n == 0) { | |||||
| if(violation) *violation = "description string must be valid UTF-8"; | |||||
| return false; | |||||
| } | |||||
| b += n; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| /* | |||||
| * These routines are private to libFLAC | |||||
| */ | |||||
| unsigned FLAC__format_get_max_rice_partition_order(unsigned blocksize, unsigned predictor_order) | |||||
| { | |||||
| return | |||||
| FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order( | |||||
| FLAC__format_get_max_rice_partition_order_from_blocksize(blocksize), | |||||
| blocksize, | |||||
| predictor_order | |||||
| ); | |||||
| } | |||||
| unsigned FLAC__format_get_max_rice_partition_order_from_blocksize(unsigned blocksize) | |||||
| { | |||||
| unsigned max_rice_partition_order = 0; | |||||
| while(!(blocksize & 1)) { | |||||
| max_rice_partition_order++; | |||||
| blocksize >>= 1; | |||||
| } | |||||
| return min(FLAC__MAX_RICE_PARTITION_ORDER, max_rice_partition_order); | |||||
| } | |||||
| unsigned FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(unsigned limit, unsigned blocksize, unsigned predictor_order) | |||||
| { | |||||
| unsigned max_rice_partition_order = limit; | |||||
| while(max_rice_partition_order > 0 && (blocksize >> max_rice_partition_order) <= predictor_order) | |||||
| max_rice_partition_order--; | |||||
| FLAC__ASSERT( | |||||
| (max_rice_partition_order == 0 && blocksize >= predictor_order) || | |||||
| (max_rice_partition_order > 0 && blocksize >> max_rice_partition_order > predictor_order) | |||||
| ); | |||||
| return max_rice_partition_order; | |||||
| } | |||||
| void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object) | |||||
| { | |||||
| FLAC__ASSERT(0 != object); | |||||
| object->parameters = 0; | |||||
| object->raw_bits = 0; | |||||
| object->capacity_by_order = 0; | |||||
| } | |||||
| void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object) | |||||
| { | |||||
| FLAC__ASSERT(0 != object); | |||||
| if(0 != object->parameters) | |||||
| free(object->parameters); | |||||
| if(0 != object->raw_bits) | |||||
| free(object->raw_bits); | |||||
| FLAC__format_entropy_coding_method_partitioned_rice_contents_init(object); | |||||
| } | |||||
| FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, unsigned max_partition_order) | |||||
| { | |||||
| FLAC__ASSERT(0 != object); | |||||
| FLAC__ASSERT(object->capacity_by_order > 0 || (0 == object->parameters && 0 == object->raw_bits)); | |||||
| if(object->capacity_by_order < max_partition_order) { | |||||
| if(0 == (object->parameters = (unsigned*)realloc(object->parameters, sizeof(unsigned)*(1 << max_partition_order)))) | |||||
| return false; | |||||
| if(0 == (object->raw_bits = (unsigned*)realloc(object->raw_bits, sizeof(unsigned)*(1 << max_partition_order)))) | |||||
| return false; | |||||
| memset(object->raw_bits, 0, sizeof(unsigned)*(1 << max_partition_order)); | |||||
| object->capacity_by_order = max_partition_order; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,49 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__PRIVATE__ALL_H | |||||
| #define FLAC__PRIVATE__ALL_H | |||||
| #include "bitmath.h" | |||||
| #include "bitreader.h" | |||||
| #include "bitwriter.h" | |||||
| #include "cpu.h" | |||||
| #include "crc.h" | |||||
| #include "fixed.h" | |||||
| #include "float.h" | |||||
| #include "format.h" | |||||
| #include "lpc.h" | |||||
| #include "md5.h" | |||||
| #include "memory.h" | |||||
| #include "metadata.h" | |||||
| #include "stream_encoder_framing.h" | |||||
| #endif | |||||
| @@ -0,0 +1,42 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__PRIVATE__BITMATH_H | |||||
| #define FLAC__PRIVATE__BITMATH_H | |||||
| #include "../../../ordinals.h" | |||||
| unsigned FLAC__bitmath_ilog2(FLAC__uint32 v); | |||||
| unsigned FLAC__bitmath_ilog2_wide(FLAC__uint64 v); | |||||
| unsigned FLAC__bitmath_silog2(int v); | |||||
| unsigned FLAC__bitmath_silog2_wide(FLAC__int64 v); | |||||
| #endif | |||||
| @@ -0,0 +1,99 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__PRIVATE__BITREADER_H | |||||
| #define FLAC__PRIVATE__BITREADER_H | |||||
| #include <stdio.h> /* for FILE */ | |||||
| #include "../../../ordinals.h" | |||||
| #include "cpu.h" | |||||
| /* | |||||
| * opaque structure definition | |||||
| */ | |||||
| struct FLAC__BitReader; | |||||
| typedef struct FLAC__BitReader FLAC__BitReader; | |||||
| typedef FLAC__bool (*FLAC__BitReaderReadCallback)(FLAC__byte buffer[], size_t *bytes, void *client_data); | |||||
| /* | |||||
| * construction, deletion, initialization, etc functions | |||||
| */ | |||||
| FLAC__BitReader *FLAC__bitreader_new(void); | |||||
| void FLAC__bitreader_delete(FLAC__BitReader *br); | |||||
| FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__CPUInfo cpu, FLAC__BitReaderReadCallback rcb, void *cd); | |||||
| void FLAC__bitreader_free(FLAC__BitReader *br); /* does not 'free(br)' */ | |||||
| FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br); | |||||
| void FLAC__bitreader_dump(const FLAC__BitReader *br, FILE *out); | |||||
| /* | |||||
| * CRC functions | |||||
| */ | |||||
| void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed); | |||||
| FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br); | |||||
| /* | |||||
| * info functions | |||||
| */ | |||||
| FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br); | |||||
| unsigned FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br); | |||||
| unsigned FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br); | |||||
| /* | |||||
| * read functions | |||||
| */ | |||||
| FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, unsigned bits); | |||||
| FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, unsigned bits); | |||||
| FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, unsigned bits); | |||||
| FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val); /*only for bits=32*/ | |||||
| FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, unsigned bits); /* WATCHOUT: does not CRC the skipped data! */ /*@@@@ add to unit tests */ | |||||
| FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, unsigned nvals); /* WATCHOUT: does not CRC the read data! */ | |||||
| FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, unsigned nvals); /* WATCHOUT: does not CRC the read data! */ | |||||
| FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, unsigned *val); | |||||
| FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, unsigned parameter); | |||||
| FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter); | |||||
| #ifndef FLAC__NO_ASM | |||||
| # ifdef FLAC__CPU_IA32 | |||||
| # ifdef FLAC__HAS_NASM | |||||
| FLAC__bool FLAC__bitreader_read_rice_signed_block_asm_ia32_bswap(FLAC__BitReader *br, int vals[], unsigned nvals, unsigned parameter); | |||||
| # endif | |||||
| # endif | |||||
| #endif | |||||
| #if 0 /* UNUSED */ | |||||
| FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, unsigned parameter); | |||||
| FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, unsigned *val, unsigned parameter); | |||||
| #endif | |||||
| FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, unsigned *rawlen); | |||||
| FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, unsigned *rawlen); | |||||
| FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br); | |||||
| #endif | |||||
| @@ -0,0 +1,103 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__PRIVATE__BITWRITER_H | |||||
| #define FLAC__PRIVATE__BITWRITER_H | |||||
| #include <stdio.h> /* for FILE */ | |||||
| #include "../../../ordinals.h" | |||||
| /* | |||||
| * opaque structure definition | |||||
| */ | |||||
| struct FLAC__BitWriter; | |||||
| typedef struct FLAC__BitWriter FLAC__BitWriter; | |||||
| /* | |||||
| * construction, deletion, initialization, etc functions | |||||
| */ | |||||
| FLAC__BitWriter *FLAC__bitwriter_new(void); | |||||
| void FLAC__bitwriter_delete(FLAC__BitWriter *bw); | |||||
| FLAC__bool FLAC__bitwriter_init(FLAC__BitWriter *bw); | |||||
| void FLAC__bitwriter_free(FLAC__BitWriter *bw); /* does not 'free(buffer)' */ | |||||
| void FLAC__bitwriter_clear(FLAC__BitWriter *bw); | |||||
| void FLAC__bitwriter_dump(const FLAC__BitWriter *bw, FILE *out); | |||||
| /* | |||||
| * CRC functions | |||||
| * | |||||
| * non-const *bw because they have to cal FLAC__bitwriter_get_buffer() | |||||
| */ | |||||
| FLAC__bool FLAC__bitwriter_get_write_crc16(FLAC__BitWriter *bw, FLAC__uint16 *crc); | |||||
| FLAC__bool FLAC__bitwriter_get_write_crc8(FLAC__BitWriter *bw, FLAC__byte *crc); | |||||
| /* | |||||
| * info functions | |||||
| */ | |||||
| FLAC__bool FLAC__bitwriter_is_byte_aligned(const FLAC__BitWriter *bw); | |||||
| unsigned FLAC__bitwriter_get_input_bits_unconsumed(const FLAC__BitWriter *bw); /* can be called anytime, returns total # of bits unconsumed */ | |||||
| /* | |||||
| * direct buffer access | |||||
| * | |||||
| * there may be no calls on the bitwriter between get and release. | |||||
| * the bitwriter continues to own the returned buffer. | |||||
| * before get, bitwriter MUST be byte aligned: check with FLAC__bitwriter_is_byte_aligned() | |||||
| */ | |||||
| FLAC__bool FLAC__bitwriter_get_buffer(FLAC__BitWriter *bw, const FLAC__byte **buffer, size_t *bytes); | |||||
| void FLAC__bitwriter_release_buffer(FLAC__BitWriter *bw); | |||||
| /* | |||||
| * write functions | |||||
| */ | |||||
| FLAC__bool FLAC__bitwriter_write_zeroes(FLAC__BitWriter *bw, unsigned bits); | |||||
| FLAC__bool FLAC__bitwriter_write_raw_uint32(FLAC__BitWriter *bw, FLAC__uint32 val, unsigned bits); | |||||
| FLAC__bool FLAC__bitwriter_write_raw_int32(FLAC__BitWriter *bw, FLAC__int32 val, unsigned bits); | |||||
| FLAC__bool FLAC__bitwriter_write_raw_uint64(FLAC__BitWriter *bw, FLAC__uint64 val, unsigned bits); | |||||
| FLAC__bool FLAC__bitwriter_write_raw_uint32_little_endian(FLAC__BitWriter *bw, FLAC__uint32 val); /*only for bits=32*/ | |||||
| FLAC__bool FLAC__bitwriter_write_byte_block(FLAC__BitWriter *bw, const FLAC__byte vals[], unsigned nvals); | |||||
| FLAC__bool FLAC__bitwriter_write_unary_unsigned(FLAC__BitWriter *bw, unsigned val); | |||||
| unsigned FLAC__bitwriter_rice_bits(FLAC__int32 val, unsigned parameter); | |||||
| #if 0 /* UNUSED */ | |||||
| unsigned FLAC__bitwriter_golomb_bits_signed(int val, unsigned parameter); | |||||
| unsigned FLAC__bitwriter_golomb_bits_unsigned(unsigned val, unsigned parameter); | |||||
| #endif | |||||
| FLAC__bool FLAC__bitwriter_write_rice_signed(FLAC__BitWriter *bw, FLAC__int32 val, unsigned parameter); | |||||
| FLAC__bool FLAC__bitwriter_write_rice_signed_block(FLAC__BitWriter *bw, const FLAC__int32 *vals, unsigned nvals, unsigned parameter); | |||||
| #if 0 /* UNUSED */ | |||||
| FLAC__bool FLAC__bitwriter_write_golomb_signed(FLAC__BitWriter *bw, int val, unsigned parameter); | |||||
| FLAC__bool FLAC__bitwriter_write_golomb_unsigned(FLAC__BitWriter *bw, unsigned val, unsigned parameter); | |||||
| #endif | |||||
| FLAC__bool FLAC__bitwriter_write_utf8_uint32(FLAC__BitWriter *bw, FLAC__uint32 val); | |||||
| FLAC__bool FLAC__bitwriter_write_utf8_uint64(FLAC__BitWriter *bw, FLAC__uint64 val); | |||||
| FLAC__bool FLAC__bitwriter_zero_pad_to_byte_boundary(FLAC__BitWriter *bw); | |||||
| #endif | |||||
| @@ -0,0 +1,88 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__PRIVATE__CPU_H | |||||
| #define FLAC__PRIVATE__CPU_H | |||||
| #include "../../../ordinals.h" | |||||
| #ifdef HAVE_CONFIG_H | |||||
| #include <config.h> | |||||
| #endif | |||||
| typedef enum { | |||||
| FLAC__CPUINFO_TYPE_IA32, | |||||
| FLAC__CPUINFO_TYPE_PPC, | |||||
| FLAC__CPUINFO_TYPE_UNKNOWN | |||||
| } FLAC__CPUInfo_Type; | |||||
| typedef struct { | |||||
| FLAC__bool cpuid; | |||||
| FLAC__bool bswap; | |||||
| FLAC__bool cmov; | |||||
| FLAC__bool mmx; | |||||
| FLAC__bool fxsr; | |||||
| FLAC__bool sse; | |||||
| FLAC__bool sse2; | |||||
| FLAC__bool sse3; | |||||
| FLAC__bool ssse3; | |||||
| FLAC__bool _3dnow; | |||||
| FLAC__bool ext3dnow; | |||||
| FLAC__bool extmmx; | |||||
| } FLAC__CPUInfo_IA32; | |||||
| typedef struct { | |||||
| FLAC__bool altivec; | |||||
| FLAC__bool ppc64; | |||||
| } FLAC__CPUInfo_PPC; | |||||
| typedef struct { | |||||
| FLAC__bool use_asm; | |||||
| FLAC__CPUInfo_Type type; | |||||
| union { | |||||
| FLAC__CPUInfo_IA32 ia32; | |||||
| FLAC__CPUInfo_PPC ppc; | |||||
| } data; | |||||
| } FLAC__CPUInfo; | |||||
| void FLAC__cpu_info(FLAC__CPUInfo *info); | |||||
| #ifndef FLAC__NO_ASM | |||||
| #ifdef FLAC__CPU_IA32 | |||||
| #ifdef FLAC__HAS_NASM | |||||
| FLAC__uint32 FLAC__cpu_have_cpuid_asm_ia32(void); | |||||
| void FLAC__cpu_info_asm_ia32(FLAC__uint32 *flags_edx, FLAC__uint32 *flags_ecx); | |||||
| FLAC__uint32 FLAC__cpu_info_extended_amd_asm_ia32(void); | |||||
| #endif | |||||
| #endif | |||||
| #endif | |||||
| #endif | |||||
| @@ -0,0 +1,61 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__PRIVATE__CRC_H | |||||
| #define FLAC__PRIVATE__CRC_H | |||||
| #include "../../../ordinals.h" | |||||
| /* 8 bit CRC generator, MSB shifted first | |||||
| ** polynomial = x^8 + x^2 + x^1 + x^0 | |||||
| ** init = 0 | |||||
| */ | |||||
| extern FLAC__byte const FLAC__crc8_table[256]; | |||||
| #define FLAC__CRC8_UPDATE(data, crc) (crc) = FLAC__crc8_table[(crc) ^ (data)]; | |||||
| void FLAC__crc8_update(const FLAC__byte data, FLAC__uint8 *crc); | |||||
| void FLAC__crc8_update_block(const FLAC__byte *data, unsigned len, FLAC__uint8 *crc); | |||||
| FLAC__uint8 FLAC__crc8(const FLAC__byte *data, unsigned len); | |||||
| /* 16 bit CRC generator, MSB shifted first | |||||
| ** polynomial = x^16 + x^15 + x^2 + x^0 | |||||
| ** init = 0 | |||||
| */ | |||||
| extern unsigned FLAC__crc16_table[256]; | |||||
| #define FLAC__CRC16_UPDATE(data, crc) (((((crc)<<8) & 0xffff) ^ FLAC__crc16_table[((crc)>>8) ^ (data)])) | |||||
| /* this alternate may be faster on some systems/compilers */ | |||||
| #if 0 | |||||
| #define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) ^ FLAC__crc16_table[((crc)>>8) ^ (data)]) & 0xffff) | |||||
| #endif | |||||
| unsigned FLAC__crc16(const FLAC__byte *data, unsigned len); | |||||
| #endif | |||||
| @@ -0,0 +1,97 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__PRIVATE__FIXED_H | |||||
| #define FLAC__PRIVATE__FIXED_H | |||||
| #ifdef HAVE_CONFIG_H | |||||
| #include <config.h> | |||||
| #endif | |||||
| #include "float.h" | |||||
| #include "format.h" | |||||
| /* | |||||
| * FLAC__fixed_compute_best_predictor() | |||||
| * -------------------------------------------------------------------- | |||||
| * Compute the best fixed predictor and the expected bits-per-sample | |||||
| * of the residual signal for each order. The _wide() version uses | |||||
| * 64-bit integers which is statistically necessary when bits-per- | |||||
| * sample + log2(blocksize) > 30 | |||||
| * | |||||
| * IN data[0,data_len-1] | |||||
| * IN data_len | |||||
| * OUT residual_bits_per_sample[0,FLAC__MAX_FIXED_ORDER] | |||||
| */ | |||||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||||
| unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); | |||||
| # ifndef FLAC__NO_ASM | |||||
| # ifdef FLAC__CPU_IA32 | |||||
| # ifdef FLAC__HAS_NASM | |||||
| unsigned FLAC__fixed_compute_best_predictor_asm_ia32_mmx_cmov(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); | |||||
| # endif | |||||
| # endif | |||||
| # endif | |||||
| unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); | |||||
| #else | |||||
| unsigned FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); | |||||
| unsigned FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], unsigned data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); | |||||
| #endif | |||||
| /* | |||||
| * FLAC__fixed_compute_residual() | |||||
| * -------------------------------------------------------------------- | |||||
| * Compute the residual signal obtained from sutracting the predicted | |||||
| * signal from the original. | |||||
| * | |||||
| * IN data[-order,data_len-1] original signal (NOTE THE INDICES!) | |||||
| * IN data_len length of original signal | |||||
| * IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order | |||||
| * OUT residual[0,data_len-1] residual signal | |||||
| */ | |||||
| void FLAC__fixed_compute_residual(const FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__int32 residual[]); | |||||
| /* | |||||
| * FLAC__fixed_restore_signal() | |||||
| * -------------------------------------------------------------------- | |||||
| * Restore the original signal by summing the residual and the | |||||
| * predictor. | |||||
| * | |||||
| * IN residual[0,data_len-1] residual signal | |||||
| * IN data_len length of original signal | |||||
| * IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order | |||||
| * *** IMPORTANT: the caller must pass in the historical samples: | |||||
| * IN data[-order,-1] previously-reconstructed historical samples | |||||
| * OUT data[0,data_len-1] original signal | |||||
| */ | |||||
| void FLAC__fixed_restore_signal(const FLAC__int32 residual[], unsigned data_len, unsigned order, FLAC__int32 data[]); | |||||
| #endif | |||||
| @@ -0,0 +1,97 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__PRIVATE__FLOAT_H | |||||
| #define FLAC__PRIVATE__FLOAT_H | |||||
| #ifdef HAVE_CONFIG_H | |||||
| #include <config.h> | |||||
| #endif | |||||
| #include "../../../ordinals.h" | |||||
| /* | |||||
| * These typedefs make it easier to ensure that integer versions of | |||||
| * the library really only contain integer operations. All the code | |||||
| * in libFLAC should use FLAC__float and FLAC__double in place of | |||||
| * float and double, and be protected by checks of the macro | |||||
| * FLAC__INTEGER_ONLY_LIBRARY. | |||||
| * | |||||
| * FLAC__real is the basic floating point type used in LPC analysis. | |||||
| */ | |||||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||||
| typedef double FLAC__double; | |||||
| typedef float FLAC__float; | |||||
| /* | |||||
| * WATCHOUT: changing FLAC__real will change the signatures of many | |||||
| * functions that have assembly language equivalents and break them. | |||||
| */ | |||||
| typedef float FLAC__real; | |||||
| #else | |||||
| /* | |||||
| * The convention for FLAC__fixedpoint is to use the upper 16 bits | |||||
| * for the integer part and lower 16 bits for the fractional part. | |||||
| */ | |||||
| typedef FLAC__int32 FLAC__fixedpoint; | |||||
| extern const FLAC__fixedpoint FLAC__FP_ZERO; | |||||
| extern const FLAC__fixedpoint FLAC__FP_ONE_HALF; | |||||
| extern const FLAC__fixedpoint FLAC__FP_ONE; | |||||
| extern const FLAC__fixedpoint FLAC__FP_LN2; | |||||
| extern const FLAC__fixedpoint FLAC__FP_E; | |||||
| #define FLAC__fixedpoint_trunc(x) ((x)>>16) | |||||
| #define FLAC__fixedpoint_mul(x, y) ( (FLAC__fixedpoint) ( ((FLAC__int64)(x)*(FLAC__int64)(y)) >> 16 ) ) | |||||
| #define FLAC__fixedpoint_div(x, y) ( (FLAC__fixedpoint) ( ( ((FLAC__int64)(x)<<32) / (FLAC__int64)(y) ) >> 16 ) ) | |||||
| /* | |||||
| * FLAC__fixedpoint_log2() | |||||
| * -------------------------------------------------------------------- | |||||
| * Returns the base-2 logarithm of the fixed-point number 'x' using an | |||||
| * algorithm by Knuth for x >= 1.0 | |||||
| * | |||||
| * 'fracbits' is the number of fractional bits of 'x'. 'fracbits' must | |||||
| * be < 32 and evenly divisible by 4 (0 is OK but not very precise). | |||||
| * | |||||
| * 'precision' roughly limits the number of iterations that are done; | |||||
| * use (unsigned)(-1) for maximum precision. | |||||
| * | |||||
| * If 'x' is less than one -- that is, x < (1<<fracbits) -- then this | |||||
| * function will punt and return 0. | |||||
| * | |||||
| * The return value will also have 'fracbits' fractional bits. | |||||
| */ | |||||
| FLAC__uint32 FLAC__fixedpoint_log2(FLAC__uint32 x, unsigned fracbits, unsigned precision); | |||||
| #endif | |||||
| #endif | |||||
| @@ -0,0 +1,44 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__PRIVATE__FORMAT_H | |||||
| #define FLAC__PRIVATE__FORMAT_H | |||||
| #include "../../../format.h" | |||||
| unsigned FLAC__format_get_max_rice_partition_order(unsigned blocksize, unsigned predictor_order); | |||||
| unsigned FLAC__format_get_max_rice_partition_order_from_blocksize(unsigned blocksize); | |||||
| unsigned FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(unsigned limit, unsigned blocksize, unsigned predictor_order); | |||||
| void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object); | |||||
| void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object); | |||||
| FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, unsigned max_partition_order); | |||||
| #endif | |||||
| @@ -0,0 +1,214 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__PRIVATE__LPC_H | |||||
| #define FLAC__PRIVATE__LPC_H | |||||
| #ifdef HAVE_CONFIG_H | |||||
| #include <config.h> | |||||
| #endif | |||||
| #include "float.h" | |||||
| #include "../../../format.h" | |||||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||||
| /* | |||||
| * FLAC__lpc_window_data() | |||||
| * -------------------------------------------------------------------- | |||||
| * Applies the given window to the data. | |||||
| * OPT: asm implementation | |||||
| * | |||||
| * IN in[0,data_len-1] | |||||
| * IN window[0,data_len-1] | |||||
| * OUT out[0,lag-1] | |||||
| * IN data_len | |||||
| */ | |||||
| void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], unsigned data_len); | |||||
| /* | |||||
| * FLAC__lpc_compute_autocorrelation() | |||||
| * -------------------------------------------------------------------- | |||||
| * Compute the autocorrelation for lags between 0 and lag-1. | |||||
| * Assumes data[] outside of [0,data_len-1] == 0. | |||||
| * Asserts that lag > 0. | |||||
| * | |||||
| * IN data[0,data_len-1] | |||||
| * IN data_len | |||||
| * IN 0 < lag <= data_len | |||||
| * OUT autoc[0,lag-1] | |||||
| */ | |||||
| void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); | |||||
| #ifndef FLAC__NO_ASM | |||||
| # ifdef FLAC__CPU_IA32 | |||||
| # ifdef FLAC__HAS_NASM | |||||
| void FLAC__lpc_compute_autocorrelation_asm_ia32(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); | |||||
| void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_4(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); | |||||
| void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_8(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); | |||||
| void FLAC__lpc_compute_autocorrelation_asm_ia32_sse_lag_12(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); | |||||
| void FLAC__lpc_compute_autocorrelation_asm_ia32_3dnow(const FLAC__real data[], unsigned data_len, unsigned lag, FLAC__real autoc[]); | |||||
| # endif | |||||
| # endif | |||||
| #endif | |||||
| /* | |||||
| * FLAC__lpc_compute_lp_coefficients() | |||||
| * -------------------------------------------------------------------- | |||||
| * Computes LP coefficients for orders 1..max_order. | |||||
| * Do not call if autoc[0] == 0.0. This means the signal is zero | |||||
| * and there is no point in calculating a predictor. | |||||
| * | |||||
| * IN autoc[0,max_order] autocorrelation values | |||||
| * IN 0 < max_order <= FLAC__MAX_LPC_ORDER max LP order to compute | |||||
| * OUT lp_coeff[0,max_order-1][0,max_order-1] LP coefficients for each order | |||||
| * *** IMPORTANT: | |||||
| * *** lp_coeff[0,max_order-1][max_order,FLAC__MAX_LPC_ORDER-1] are untouched | |||||
| * OUT error[0,max_order-1] error for each order (more | |||||
| * specifically, the variance of | |||||
| * the error signal times # of | |||||
| * samples in the signal) | |||||
| * | |||||
| * Example: if max_order is 9, the LP coefficients for order 9 will be | |||||
| * in lp_coeff[8][0,8], the LP coefficients for order 8 will be | |||||
| * in lp_coeff[7][0,7], etc. | |||||
| */ | |||||
| void FLAC__lpc_compute_lp_coefficients(const FLAC__real autoc[], unsigned *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], FLAC__double error[]); | |||||
| /* | |||||
| * FLAC__lpc_quantize_coefficients() | |||||
| * -------------------------------------------------------------------- | |||||
| * Quantizes the LP coefficients. NOTE: precision + bits_per_sample | |||||
| * must be less than 32 (sizeof(FLAC__int32)*8). | |||||
| * | |||||
| * IN lp_coeff[0,order-1] LP coefficients | |||||
| * IN order LP order | |||||
| * IN FLAC__MIN_QLP_COEFF_PRECISION < precision | |||||
| * desired precision (in bits, including sign | |||||
| * bit) of largest coefficient | |||||
| * OUT qlp_coeff[0,order-1] quantized coefficients | |||||
| * OUT shift # of bits to shift right to get approximated | |||||
| * LP coefficients. NOTE: could be negative. | |||||
| * RETURN 0 => quantization OK | |||||
| * 1 => coefficients require too much shifting for *shift to | |||||
| * fit in the LPC subframe header. 'shift' is unset. | |||||
| * 2 => coefficients are all zero, which is bad. 'shift' is | |||||
| * unset. | |||||
| */ | |||||
| int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], unsigned order, unsigned precision, FLAC__int32 qlp_coeff[], int *shift); | |||||
| /* | |||||
| * FLAC__lpc_compute_residual_from_qlp_coefficients() | |||||
| * -------------------------------------------------------------------- | |||||
| * Compute the residual signal obtained from sutracting the predicted | |||||
| * signal from the original. | |||||
| * | |||||
| * IN data[-order,data_len-1] original signal (NOTE THE INDICES!) | |||||
| * IN data_len length of original signal | |||||
| * IN qlp_coeff[0,order-1] quantized LP coefficients | |||||
| * IN order > 0 LP order | |||||
| * IN lp_quantization quantization of LP coefficients in bits | |||||
| * OUT residual[0,data_len-1] residual signal | |||||
| */ | |||||
| void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); | |||||
| void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); | |||||
| #ifndef FLAC__NO_ASM | |||||
| # ifdef FLAC__CPU_IA32 | |||||
| # ifdef FLAC__HAS_NASM | |||||
| void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); | |||||
| void FLAC__lpc_compute_residual_from_qlp_coefficients_asm_ia32_mmx(const FLAC__int32 *data, unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 residual[]); | |||||
| # endif | |||||
| # endif | |||||
| #endif | |||||
| #endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ | |||||
| /* | |||||
| * FLAC__lpc_restore_signal() | |||||
| * -------------------------------------------------------------------- | |||||
| * Restore the original signal by summing the residual and the | |||||
| * predictor. | |||||
| * | |||||
| * IN residual[0,data_len-1] residual signal | |||||
| * IN data_len length of original signal | |||||
| * IN qlp_coeff[0,order-1] quantized LP coefficients | |||||
| * IN order > 0 LP order | |||||
| * IN lp_quantization quantization of LP coefficients in bits | |||||
| * *** IMPORTANT: the caller must pass in the historical samples: | |||||
| * IN data[-order,-1] previously-reconstructed historical samples | |||||
| * OUT data[0,data_len-1] original signal | |||||
| */ | |||||
| void FLAC__lpc_restore_signal(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); | |||||
| void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); | |||||
| #ifndef FLAC__NO_ASM | |||||
| # ifdef FLAC__CPU_IA32 | |||||
| # ifdef FLAC__HAS_NASM | |||||
| void FLAC__lpc_restore_signal_asm_ia32(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); | |||||
| void FLAC__lpc_restore_signal_asm_ia32_mmx(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); | |||||
| # endif /* FLAC__HAS_NASM */ | |||||
| # elif defined FLAC__CPU_PPC | |||||
| void FLAC__lpc_restore_signal_asm_ppc_altivec_16(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); | |||||
| void FLAC__lpc_restore_signal_asm_ppc_altivec_16_order8(const FLAC__int32 residual[], unsigned data_len, const FLAC__int32 qlp_coeff[], unsigned order, int lp_quantization, FLAC__int32 data[]); | |||||
| # endif/* FLAC__CPU_IA32 || FLAC__CPU_PPC */ | |||||
| #endif /* FLAC__NO_ASM */ | |||||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||||
| /* | |||||
| * FLAC__lpc_compute_expected_bits_per_residual_sample() | |||||
| * -------------------------------------------------------------------- | |||||
| * Compute the expected number of bits per residual signal sample | |||||
| * based on the LP error (which is related to the residual variance). | |||||
| * | |||||
| * IN lpc_error >= 0.0 error returned from calculating LP coefficients | |||||
| * IN total_samples > 0 # of samples in residual signal | |||||
| * RETURN expected bits per sample | |||||
| */ | |||||
| FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample(FLAC__double lpc_error, unsigned total_samples); | |||||
| FLAC__double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(FLAC__double lpc_error, FLAC__double error_scale); | |||||
| /* | |||||
| * FLAC__lpc_compute_best_order() | |||||
| * -------------------------------------------------------------------- | |||||
| * Compute the best order from the array of signal errors returned | |||||
| * during coefficient computation. | |||||
| * | |||||
| * IN lpc_error[0,max_order-1] >= 0.0 error returned from calculating LP coefficients | |||||
| * IN max_order > 0 max LP order | |||||
| * IN total_samples > 0 # of samples in residual signal | |||||
| * IN overhead_bits_per_order # of bits overhead for each increased LP order | |||||
| * (includes warmup sample size and quantized LP coefficient) | |||||
| * RETURN [1,max_order] best order | |||||
| */ | |||||
| unsigned FLAC__lpc_compute_best_order(const FLAC__double lpc_error[], unsigned max_order, unsigned total_samples, unsigned overhead_bits_per_order); | |||||
| #endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ | |||||
| #endif | |||||
| @@ -0,0 +1,44 @@ | |||||
| #ifndef FLAC__PRIVATE__MD5_H | |||||
| #define FLAC__PRIVATE__MD5_H | |||||
| /* | |||||
| * This is the header file for the MD5 message-digest algorithm. | |||||
| * The algorithm is due to Ron Rivest. This code was | |||||
| * written by Colin Plumb in 1993, no copyright is claimed. | |||||
| * This code is in the public domain; do with it what you wish. | |||||
| * | |||||
| * Equivalent code is available from RSA Data Security, Inc. | |||||
| * This code has been tested against that, and is equivalent, | |||||
| * except that you don't need to include two pages of legalese | |||||
| * with every copy. | |||||
| * | |||||
| * To compute the message digest of a chunk of bytes, declare an | |||||
| * MD5Context structure, pass it to MD5Init, call MD5Update as | |||||
| * needed on buffers full of bytes, and then call MD5Final, which | |||||
| * will fill a supplied 16-byte array with the digest. | |||||
| * | |||||
| * Changed so as no longer to depend on Colin Plumb's `usual.h' | |||||
| * header definitions; now uses stuff from dpkg's config.h | |||||
| * - Ian Jackson <ijackson@nyx.cs.du.edu>. | |||||
| * Still in the public domain. | |||||
| * | |||||
| * Josh Coalson: made some changes to integrate with libFLAC. | |||||
| * Still in the public domain, with no warranty. | |||||
| */ | |||||
| #include "../../../ordinals.h" | |||||
| typedef struct { | |||||
| FLAC__uint32 in[16]; | |||||
| FLAC__uint32 buf[4]; | |||||
| FLAC__uint32 bytes[2]; | |||||
| FLAC__byte *internal_buf; | |||||
| size_t capacity; | |||||
| } FLAC__MD5Context; | |||||
| void FLAC__MD5Init(FLAC__MD5Context *context); | |||||
| void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *context); | |||||
| FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample); | |||||
| #endif | |||||
| @@ -0,0 +1,56 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__PRIVATE__MEMORY_H | |||||
| #define FLAC__PRIVATE__MEMORY_H | |||||
| #ifdef HAVE_CONFIG_H | |||||
| #include <config.h> | |||||
| #endif | |||||
| #include <stdlib.h> /* for size_t */ | |||||
| #include "float.h" | |||||
| #include "../../../ordinals.h" /* for FLAC__bool */ | |||||
| /* Returns the unaligned address returned by malloc. | |||||
| * Use free() on this address to deallocate. | |||||
| */ | |||||
| void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address); | |||||
| FLAC__bool FLAC__memory_alloc_aligned_int32_array(unsigned elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer); | |||||
| FLAC__bool FLAC__memory_alloc_aligned_uint32_array(unsigned elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer); | |||||
| FLAC__bool FLAC__memory_alloc_aligned_uint64_array(unsigned elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer); | |||||
| FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(unsigned elements, unsigned **unaligned_pointer, unsigned **aligned_pointer); | |||||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||||
| FLAC__bool FLAC__memory_alloc_aligned_real_array(unsigned elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer); | |||||
| #endif | |||||
| #endif | |||||
| @@ -0,0 +1,45 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__PRIVATE__METADATA_H | |||||
| #define FLAC__PRIVATE__METADATA_H | |||||
| #include "metadata.h" | |||||
| /* WATCHOUT: all malloc()ed data in the block is free()ed; this may not | |||||
| * be a consistent state (e.g. PICTURE) or equivalent to the initial | |||||
| * state after FLAC__metadata_object_new() | |||||
| */ | |||||
| void FLAC__metadata_object_delete_data(FLAC__StreamMetadata *object); | |||||
| void FLAC__metadata_object_cuesheet_track_delete_data(FLAC__StreamMetadata_CueSheet_Track *object); | |||||
| #endif | |||||
| @@ -0,0 +1,45 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__PRIVATE__STREAM_ENCODER_FRAMING_H | |||||
| #define FLAC__PRIVATE__STREAM_ENCODER_FRAMING_H | |||||
| #include "../../../format.h" | |||||
| #include "bitwriter.h" | |||||
| FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitWriter *bw); | |||||
| FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__BitWriter *bw); | |||||
| FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw); | |||||
| FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw); | |||||
| FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw); | |||||
| FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, unsigned samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw); | |||||
| #endif | |||||
| @@ -0,0 +1,71 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__PRIVATE__WINDOW_H | |||||
| #define FLAC__PRIVATE__WINDOW_H | |||||
| #ifdef HAVE_CONFIG_H | |||||
| #include <config.h> | |||||
| #endif | |||||
| #include "float.h" | |||||
| #include "../../../format.h" | |||||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||||
| /* | |||||
| * FLAC__window_*() | |||||
| * -------------------------------------------------------------------- | |||||
| * Calculates window coefficients according to different apodization | |||||
| * functions. | |||||
| * | |||||
| * OUT window[0,L-1] | |||||
| * IN L (number of points in window) | |||||
| */ | |||||
| void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L); | |||||
| void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L); | |||||
| void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L); | |||||
| void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L); | |||||
| void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L); | |||||
| void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L); | |||||
| void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev); /* 0.0 < stddev <= 0.5 */ | |||||
| void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L); | |||||
| void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L); | |||||
| void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L); | |||||
| void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L); | |||||
| void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L); | |||||
| void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L); | |||||
| void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p); | |||||
| void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L); | |||||
| #endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ | |||||
| #endif | |||||
| @@ -0,0 +1,38 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__PROTECTED__ALL_H | |||||
| #define FLAC__PROTECTED__ALL_H | |||||
| #include "stream_decoder.h" | |||||
| #include "stream_encoder.h" | |||||
| #endif | |||||
| @@ -0,0 +1,58 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__PROTECTED__STREAM_DECODER_H | |||||
| #define FLAC__PROTECTED__STREAM_DECODER_H | |||||
| #include "../../../stream_decoder.h" | |||||
| #if FLAC__HAS_OGG | |||||
| #include "include/private/ogg_decoder_aspect.h" | |||||
| #endif | |||||
| typedef struct FLAC__StreamDecoderProtected { | |||||
| FLAC__StreamDecoderState state; | |||||
| unsigned channels; | |||||
| FLAC__ChannelAssignment channel_assignment; | |||||
| unsigned bits_per_sample; | |||||
| unsigned sample_rate; /* in Hz */ | |||||
| unsigned blocksize; /* in samples (per channel) */ | |||||
| FLAC__bool md5_checking; /* if true, generate MD5 signature of decoded data and compare against signature in the STREAMINFO metadata block */ | |||||
| #if FLAC__HAS_OGG | |||||
| FLAC__OggDecoderAspect ogg_decoder_aspect; | |||||
| #endif | |||||
| } FLAC__StreamDecoderProtected; | |||||
| /* | |||||
| * return the number of input bytes consumed | |||||
| */ | |||||
| unsigned FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder); | |||||
| #endif | |||||
| @@ -0,0 +1,110 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__PROTECTED__STREAM_ENCODER_H | |||||
| #define FLAC__PROTECTED__STREAM_ENCODER_H | |||||
| #include "../../../stream_encoder.h" | |||||
| #if FLAC__HAS_OGG | |||||
| #include "private/ogg_encoder_aspect.h" | |||||
| #endif | |||||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||||
| #include "../private/float.h" | |||||
| #define FLAC__MAX_APODIZATION_FUNCTIONS 32 | |||||
| typedef enum { | |||||
| FLAC__APODIZATION_BARTLETT, | |||||
| FLAC__APODIZATION_BARTLETT_HANN, | |||||
| FLAC__APODIZATION_BLACKMAN, | |||||
| FLAC__APODIZATION_BLACKMAN_HARRIS_4TERM_92DB_SIDELOBE, | |||||
| FLAC__APODIZATION_CONNES, | |||||
| FLAC__APODIZATION_FLATTOP, | |||||
| FLAC__APODIZATION_GAUSS, | |||||
| FLAC__APODIZATION_HAMMING, | |||||
| FLAC__APODIZATION_HANN, | |||||
| FLAC__APODIZATION_KAISER_BESSEL, | |||||
| FLAC__APODIZATION_NUTTALL, | |||||
| FLAC__APODIZATION_RECTANGLE, | |||||
| FLAC__APODIZATION_TRIANGLE, | |||||
| FLAC__APODIZATION_TUKEY, | |||||
| FLAC__APODIZATION_WELCH | |||||
| } FLAC__ApodizationFunction; | |||||
| typedef struct { | |||||
| FLAC__ApodizationFunction type; | |||||
| union { | |||||
| struct { | |||||
| FLAC__real stddev; | |||||
| } gauss; | |||||
| struct { | |||||
| FLAC__real p; | |||||
| } tukey; | |||||
| } parameters; | |||||
| } FLAC__ApodizationSpecification; | |||||
| #endif // #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||||
| typedef struct FLAC__StreamEncoderProtected { | |||||
| FLAC__StreamEncoderState state; | |||||
| FLAC__bool verify; | |||||
| FLAC__bool streamable_subset; | |||||
| FLAC__bool do_md5; | |||||
| FLAC__bool do_mid_side_stereo; | |||||
| FLAC__bool loose_mid_side_stereo; | |||||
| unsigned channels; | |||||
| unsigned bits_per_sample; | |||||
| unsigned sample_rate; | |||||
| unsigned blocksize; | |||||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||||
| unsigned num_apodizations; | |||||
| FLAC__ApodizationSpecification apodizations[FLAC__MAX_APODIZATION_FUNCTIONS]; | |||||
| #endif | |||||
| unsigned max_lpc_order; | |||||
| unsigned qlp_coeff_precision; | |||||
| FLAC__bool do_qlp_coeff_prec_search; | |||||
| FLAC__bool do_exhaustive_model_search; | |||||
| FLAC__bool do_escape_coding; | |||||
| unsigned min_residual_partition_order; | |||||
| unsigned max_residual_partition_order; | |||||
| unsigned rice_parameter_search_dist; | |||||
| FLAC__uint64 total_samples_estimate; | |||||
| FLAC__StreamMetadata **metadata; | |||||
| unsigned num_metadata_blocks; | |||||
| FLAC__uint64 streaminfo_offset, seektable_offset, audio_offset; | |||||
| #if FLAC__HAS_OGG | |||||
| FLAC__OggEncoderAspect ogg_encoder_aspect; | |||||
| #endif | |||||
| } FLAC__StreamEncoderProtected; | |||||
| #endif | |||||
| @@ -0,0 +1,42 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| // This file is included at the start of each FLAC .c file, just to do a few housekeeping | |||||
| // tasks.. | |||||
| #include "../../../../../juce_Config.h" | |||||
| #define VERSION "1.2.1" | |||||
| #define FLAC__NO_DLL 1 | |||||
| #ifdef _MSC_VER | |||||
| #pragma warning (disable: 4267 4127 4244 4996 4100 4701 4702 4013 4133 4206 4312) | |||||
| #endif | |||||
| #if ! (defined (_WIN32) || defined (_WIN64) || defined (LINUX)) | |||||
| #define FLAC__SYS_DARWIN 1 | |||||
| #endif | |||||
| @@ -0,0 +1,431 @@ | |||||
| #include "juce_FlacHeader.h" | |||||
| #if JUCE_USE_FLAC | |||||
| #if HAVE_CONFIG_H | |||||
| # include <config.h> | |||||
| #endif | |||||
| #include <stdlib.h> /* for malloc() */ | |||||
| #include <string.h> /* for memcpy() */ | |||||
| #include "include/private/md5.h" | |||||
| #include "../alloc.h" | |||||
| #ifndef FLaC__INLINE | |||||
| #define FLaC__INLINE | |||||
| #endif | |||||
| /* | |||||
| * This code implements the MD5 message-digest algorithm. | |||||
| * The algorithm is due to Ron Rivest. This code was | |||||
| * written by Colin Plumb in 1993, no copyright is claimed. | |||||
| * This code is in the public domain; do with it what you wish. | |||||
| * | |||||
| * Equivalent code is available from RSA Data Security, Inc. | |||||
| * This code has been tested against that, and is equivalent, | |||||
| * except that you don't need to include two pages of legalese | |||||
| * with every copy. | |||||
| * | |||||
| * To compute the message digest of a chunk of bytes, declare an | |||||
| * MD5Context structure, pass it to MD5Init, call MD5Update as | |||||
| * needed on buffers full of bytes, and then call MD5Final, which | |||||
| * will fill a supplied 16-byte array with the digest. | |||||
| * | |||||
| * Changed so as no longer to depend on Colin Plumb's `usual.h' header | |||||
| * definitions; now uses stuff from dpkg's config.h. | |||||
| * - Ian Jackson <ijackson@nyx.cs.du.edu>. | |||||
| * Still in the public domain. | |||||
| * | |||||
| * Josh Coalson: made some changes to integrate with libFLAC. | |||||
| * Still in the public domain. | |||||
| */ | |||||
| /* The four core functions - F1 is optimized somewhat */ | |||||
| /* #define F1(x, y, z) (x & y | ~x & z) */ | |||||
| #define F1(x, y, z) (z ^ (x & (y ^ z))) | |||||
| #define F2(x, y, z) F1(z, x, y) | |||||
| #define F3(x, y, z) (x ^ y ^ z) | |||||
| #define F4(x, y, z) (y ^ (x | ~z)) | |||||
| /* This is the central step in the MD5 algorithm. */ | |||||
| #define MD5STEP(f,w,x,y,z,in,s) \ | |||||
| (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x) | |||||
| /* | |||||
| * The core of the MD5 algorithm, this alters an existing MD5 hash to | |||||
| * reflect the addition of 16 longwords of new data. MD5Update blocks | |||||
| * the data and converts bytes into longwords for this routine. | |||||
| */ | |||||
| static void FLAC__MD5Transform(FLAC__uint32 buf[4], FLAC__uint32 const in[16]) | |||||
| { | |||||
| register FLAC__uint32 a, b, c, d; | |||||
| a = buf[0]; | |||||
| b = buf[1]; | |||||
| c = buf[2]; | |||||
| d = buf[3]; | |||||
| MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); | |||||
| MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); | |||||
| MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); | |||||
| MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); | |||||
| MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); | |||||
| MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); | |||||
| MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); | |||||
| MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); | |||||
| MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); | |||||
| MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); | |||||
| MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); | |||||
| MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); | |||||
| MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); | |||||
| MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); | |||||
| MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); | |||||
| MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); | |||||
| MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); | |||||
| MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); | |||||
| MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); | |||||
| MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); | |||||
| MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); | |||||
| MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); | |||||
| MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); | |||||
| MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); | |||||
| MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); | |||||
| MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); | |||||
| MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); | |||||
| MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); | |||||
| MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); | |||||
| MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); | |||||
| MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); | |||||
| MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); | |||||
| MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); | |||||
| MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); | |||||
| MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); | |||||
| MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); | |||||
| MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); | |||||
| MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); | |||||
| MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); | |||||
| MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); | |||||
| MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); | |||||
| MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); | |||||
| MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); | |||||
| MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); | |||||
| MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); | |||||
| MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); | |||||
| MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); | |||||
| MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); | |||||
| MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); | |||||
| MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); | |||||
| MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); | |||||
| MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); | |||||
| MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); | |||||
| MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); | |||||
| MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); | |||||
| MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); | |||||
| MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); | |||||
| MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); | |||||
| MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); | |||||
| MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); | |||||
| MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); | |||||
| MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); | |||||
| MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); | |||||
| MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); | |||||
| buf[0] += a; | |||||
| buf[1] += b; | |||||
| buf[2] += c; | |||||
| buf[3] += d; | |||||
| } | |||||
| #if WORDS_BIGENDIAN | |||||
| //@@@@@@ OPT: use bswap/intrinsics | |||||
| static void byteSwap(FLAC__uint32 *buf, unsigned words) | |||||
| { | |||||
| register FLAC__uint32 x; | |||||
| do { | |||||
| x = *buf; | |||||
| x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); | |||||
| *buf++ = (x >> 16) | (x << 16); | |||||
| } while (--words); | |||||
| } | |||||
| static void byteSwapX16(FLAC__uint32 *buf) | |||||
| { | |||||
| register FLAC__uint32 x; | |||||
| x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); | |||||
| x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); | |||||
| x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); | |||||
| x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); | |||||
| x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); | |||||
| x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); | |||||
| x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); | |||||
| x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); | |||||
| x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); | |||||
| x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); | |||||
| x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); | |||||
| x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); | |||||
| x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); | |||||
| x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); | |||||
| x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); | |||||
| x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf = (x >> 16) | (x << 16); | |||||
| } | |||||
| #else | |||||
| #define byteSwap(buf, words) | |||||
| #define byteSwapX16(buf) | |||||
| #endif | |||||
| /* | |||||
| * Update context to reflect the concatenation of another buffer full | |||||
| * of bytes. | |||||
| */ | |||||
| static void FLAC__MD5Update(FLAC__MD5Context *ctx, FLAC__byte const *buf, unsigned len) | |||||
| { | |||||
| FLAC__uint32 t; | |||||
| /* Update byte count */ | |||||
| t = ctx->bytes[0]; | |||||
| if ((ctx->bytes[0] = t + len) < t) | |||||
| ctx->bytes[1]++; /* Carry from low to high */ | |||||
| t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ | |||||
| if (t > len) { | |||||
| memcpy((FLAC__byte *)ctx->in + 64 - t, buf, len); | |||||
| return; | |||||
| } | |||||
| /* First chunk is an odd size */ | |||||
| memcpy((FLAC__byte *)ctx->in + 64 - t, buf, t); | |||||
| byteSwapX16(ctx->in); | |||||
| FLAC__MD5Transform(ctx->buf, ctx->in); | |||||
| buf += t; | |||||
| len -= t; | |||||
| /* Process data in 64-byte chunks */ | |||||
| while (len >= 64) { | |||||
| memcpy(ctx->in, buf, 64); | |||||
| byteSwapX16(ctx->in); | |||||
| FLAC__MD5Transform(ctx->buf, ctx->in); | |||||
| buf += 64; | |||||
| len -= 64; | |||||
| } | |||||
| /* Handle any remaining bytes of data. */ | |||||
| memcpy(ctx->in, buf, len); | |||||
| } | |||||
| /* | |||||
| * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious | |||||
| * initialization constants. | |||||
| */ | |||||
| void FLAC__MD5Init(FLAC__MD5Context *ctx) | |||||
| { | |||||
| ctx->buf[0] = 0x67452301; | |||||
| ctx->buf[1] = 0xefcdab89; | |||||
| ctx->buf[2] = 0x98badcfe; | |||||
| ctx->buf[3] = 0x10325476; | |||||
| ctx->bytes[0] = 0; | |||||
| ctx->bytes[1] = 0; | |||||
| ctx->internal_buf = 0; | |||||
| ctx->capacity = 0; | |||||
| } | |||||
| /* | |||||
| * Final wrapup - pad to 64-byte boundary with the bit pattern | |||||
| * 1 0* (64-bit count of bits processed, MSB-first) | |||||
| */ | |||||
| void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *ctx) | |||||
| { | |||||
| int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ | |||||
| FLAC__byte *p = (FLAC__byte *)ctx->in + count; | |||||
| /* Set the first char of padding to 0x80. There is always room. */ | |||||
| *p++ = 0x80; | |||||
| /* Bytes of padding needed to make 56 bytes (-8..55) */ | |||||
| count = 56 - 1 - count; | |||||
| if (count < 0) { /* Padding forces an extra block */ | |||||
| memset(p, 0, count + 8); | |||||
| byteSwapX16(ctx->in); | |||||
| FLAC__MD5Transform(ctx->buf, ctx->in); | |||||
| p = (FLAC__byte *)ctx->in; | |||||
| count = 56; | |||||
| } | |||||
| memset(p, 0, count); | |||||
| byteSwap(ctx->in, 14); | |||||
| /* Append length in bits and transform */ | |||||
| ctx->in[14] = ctx->bytes[0] << 3; | |||||
| ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; | |||||
| FLAC__MD5Transform(ctx->buf, ctx->in); | |||||
| byteSwap(ctx->buf, 4); | |||||
| memcpy(digest, ctx->buf, 16); | |||||
| memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ | |||||
| if(0 != ctx->internal_buf) { | |||||
| free(ctx->internal_buf); | |||||
| ctx->internal_buf = 0; | |||||
| ctx->capacity = 0; | |||||
| } | |||||
| } | |||||
| /* | |||||
| * Convert the incoming audio signal to a byte stream | |||||
| */ | |||||
| static void format_input_(FLAC__byte *buf, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample) | |||||
| { | |||||
| unsigned channel, sample; | |||||
| register FLAC__int32 a_word; | |||||
| register FLAC__byte *buf_ = buf; | |||||
| #if WORDS_BIGENDIAN | |||||
| #else | |||||
| if(channels == 2 && bytes_per_sample == 2) { | |||||
| FLAC__int16 *buf1_ = ((FLAC__int16*)buf_) + 1; | |||||
| memcpy(buf_, signal[0], sizeof(FLAC__int32) * samples); | |||||
| for(sample = 0; sample < samples; sample++, buf1_+=2) | |||||
| *buf1_ = (FLAC__int16)signal[1][sample]; | |||||
| } | |||||
| else if(channels == 1 && bytes_per_sample == 2) { | |||||
| FLAC__int16 *buf1_ = (FLAC__int16*)buf_; | |||||
| for(sample = 0; sample < samples; sample++) | |||||
| *buf1_++ = (FLAC__int16)signal[0][sample]; | |||||
| } | |||||
| else | |||||
| #endif | |||||
| if(bytes_per_sample == 2) { | |||||
| if(channels == 2) { | |||||
| for(sample = 0; sample < samples; sample++) { | |||||
| a_word = signal[0][sample]; | |||||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||||
| *buf_++ = (FLAC__byte)a_word; | |||||
| a_word = signal[1][sample]; | |||||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||||
| *buf_++ = (FLAC__byte)a_word; | |||||
| } | |||||
| } | |||||
| else if(channels == 1) { | |||||
| for(sample = 0; sample < samples; sample++) { | |||||
| a_word = signal[0][sample]; | |||||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||||
| *buf_++ = (FLAC__byte)a_word; | |||||
| } | |||||
| } | |||||
| else { | |||||
| for(sample = 0; sample < samples; sample++) { | |||||
| for(channel = 0; channel < channels; channel++) { | |||||
| a_word = signal[channel][sample]; | |||||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||||
| *buf_++ = (FLAC__byte)a_word; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| else if(bytes_per_sample == 3) { | |||||
| if(channels == 2) { | |||||
| for(sample = 0; sample < samples; sample++) { | |||||
| a_word = signal[0][sample]; | |||||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||||
| *buf_++ = (FLAC__byte)a_word; | |||||
| a_word = signal[1][sample]; | |||||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||||
| *buf_++ = (FLAC__byte)a_word; | |||||
| } | |||||
| } | |||||
| else if(channels == 1) { | |||||
| for(sample = 0; sample < samples; sample++) { | |||||
| a_word = signal[0][sample]; | |||||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||||
| *buf_++ = (FLAC__byte)a_word; | |||||
| } | |||||
| } | |||||
| else { | |||||
| for(sample = 0; sample < samples; sample++) { | |||||
| for(channel = 0; channel < channels; channel++) { | |||||
| a_word = signal[channel][sample]; | |||||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||||
| *buf_++ = (FLAC__byte)a_word; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| else if(bytes_per_sample == 1) { | |||||
| if(channels == 2) { | |||||
| for(sample = 0; sample < samples; sample++) { | |||||
| a_word = signal[0][sample]; | |||||
| *buf_++ = (FLAC__byte)a_word; | |||||
| a_word = signal[1][sample]; | |||||
| *buf_++ = (FLAC__byte)a_word; | |||||
| } | |||||
| } | |||||
| else if(channels == 1) { | |||||
| for(sample = 0; sample < samples; sample++) { | |||||
| a_word = signal[0][sample]; | |||||
| *buf_++ = (FLAC__byte)a_word; | |||||
| } | |||||
| } | |||||
| else { | |||||
| for(sample = 0; sample < samples; sample++) { | |||||
| for(channel = 0; channel < channels; channel++) { | |||||
| a_word = signal[channel][sample]; | |||||
| *buf_++ = (FLAC__byte)a_word; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| else { /* bytes_per_sample == 4, maybe optimize more later */ | |||||
| for(sample = 0; sample < samples; sample++) { | |||||
| for(channel = 0; channel < channels; channel++) { | |||||
| a_word = signal[channel][sample]; | |||||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||||
| *buf_++ = (FLAC__byte)a_word; a_word >>= 8; | |||||
| *buf_++ = (FLAC__byte)a_word; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| /* | |||||
| * Convert the incoming audio signal to a byte stream and FLAC__MD5Update it. | |||||
| */ | |||||
| FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], unsigned channels, unsigned samples, unsigned bytes_per_sample) | |||||
| { | |||||
| const size_t bytes_needed = (size_t)channels * (size_t)samples * (size_t)bytes_per_sample; | |||||
| /* overflow check */ | |||||
| if((size_t)channels > SIZE_MAX / (size_t)bytes_per_sample) | |||||
| return false; | |||||
| if((size_t)channels * (size_t)bytes_per_sample > SIZE_MAX / (size_t)samples) | |||||
| return false; | |||||
| if(ctx->capacity < bytes_needed) { | |||||
| FLAC__byte *tmp = (FLAC__byte*)realloc(ctx->internal_buf, bytes_needed); | |||||
| if(0 == tmp) { | |||||
| free(ctx->internal_buf); | |||||
| if(0 == (ctx->internal_buf = (FLAC__byte*)safe_malloc_(bytes_needed))) | |||||
| return false; | |||||
| } | |||||
| ctx->internal_buf = tmp; | |||||
| ctx->capacity = bytes_needed; | |||||
| } | |||||
| format_input_(ctx->internal_buf, signal, channels, samples, bytes_per_sample); | |||||
| FLAC__MD5Update(ctx, ctx->internal_buf, bytes_needed); | |||||
| return true; | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,227 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 "juce_FlacHeader.h" | |||||
| #if JUCE_USE_FLAC | |||||
| #if HAVE_CONFIG_H | |||||
| # include <config.h> | |||||
| #endif | |||||
| #include "include/private/memory.h" | |||||
| #include "../assert.h" | |||||
| #include "../alloc.h" | |||||
| void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address) | |||||
| { | |||||
| void *x; | |||||
| FLAC__ASSERT(0 != aligned_address); | |||||
| #ifdef FLAC__ALIGN_MALLOC_DATA | |||||
| /* align on 32-byte (256-bit) boundary */ | |||||
| x = safe_malloc_add_2op_(bytes, /*+*/31); | |||||
| #ifdef SIZEOF_VOIDP | |||||
| #if SIZEOF_VOIDP == 4 | |||||
| /* could do *aligned_address = x + ((unsigned) (32 - (((unsigned)x) & 31))) & 31; */ | |||||
| *aligned_address = (void*)(((unsigned)x + 31) & -32); | |||||
| #elif SIZEOF_VOIDP == 8 | |||||
| *aligned_address = (void*)(((FLAC__uint64)x + 31) & (FLAC__uint64)(-((FLAC__int64)32))); | |||||
| #else | |||||
| # error Unsupported sizeof(void*) | |||||
| #endif | |||||
| #else | |||||
| /* there's got to be a better way to do this right for all archs */ | |||||
| if(sizeof(void*) == sizeof(unsigned)) | |||||
| *aligned_address = (void*)(((unsigned)x + 31) & -32); | |||||
| else if(sizeof(void*) == sizeof(FLAC__uint64)) | |||||
| *aligned_address = (void*)(((FLAC__uint64)x + 31) & (FLAC__uint64)(-((FLAC__int64)32))); | |||||
| else | |||||
| return 0; | |||||
| #endif | |||||
| #else | |||||
| x = safe_malloc_(bytes); | |||||
| *aligned_address = x; | |||||
| #endif | |||||
| return x; | |||||
| } | |||||
| FLAC__bool FLAC__memory_alloc_aligned_int32_array(unsigned elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer) | |||||
| { | |||||
| FLAC__int32 *pu; /* unaligned pointer */ | |||||
| union { /* union needed to comply with C99 pointer aliasing rules */ | |||||
| FLAC__int32 *pa; /* aligned pointer */ | |||||
| void *pv; /* aligned pointer alias */ | |||||
| } u; | |||||
| FLAC__ASSERT(elements > 0); | |||||
| FLAC__ASSERT(0 != unaligned_pointer); | |||||
| FLAC__ASSERT(0 != aligned_pointer); | |||||
| FLAC__ASSERT(unaligned_pointer != aligned_pointer); | |||||
| if((size_t)elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ | |||||
| return false; | |||||
| pu = (FLAC__int32*)FLAC__memory_alloc_aligned(sizeof(*pu) * (size_t)elements, &u.pv); | |||||
| if(0 == pu) { | |||||
| return false; | |||||
| } | |||||
| else { | |||||
| if(*unaligned_pointer != 0) | |||||
| free(*unaligned_pointer); | |||||
| *unaligned_pointer = pu; | |||||
| *aligned_pointer = u.pa; | |||||
| return true; | |||||
| } | |||||
| } | |||||
| FLAC__bool FLAC__memory_alloc_aligned_uint32_array(unsigned elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer) | |||||
| { | |||||
| FLAC__uint32 *pu; /* unaligned pointer */ | |||||
| union { /* union needed to comply with C99 pointer aliasing rules */ | |||||
| FLAC__uint32 *pa; /* aligned pointer */ | |||||
| void *pv; /* aligned pointer alias */ | |||||
| } u; | |||||
| FLAC__ASSERT(elements > 0); | |||||
| FLAC__ASSERT(0 != unaligned_pointer); | |||||
| FLAC__ASSERT(0 != aligned_pointer); | |||||
| FLAC__ASSERT(unaligned_pointer != aligned_pointer); | |||||
| if((size_t)elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ | |||||
| return false; | |||||
| pu = (FLAC__uint32*)FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); | |||||
| if(0 == pu) { | |||||
| return false; | |||||
| } | |||||
| else { | |||||
| if(*unaligned_pointer != 0) | |||||
| free(*unaligned_pointer); | |||||
| *unaligned_pointer = pu; | |||||
| *aligned_pointer = u.pa; | |||||
| return true; | |||||
| } | |||||
| } | |||||
| FLAC__bool FLAC__memory_alloc_aligned_uint64_array(unsigned elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer) | |||||
| { | |||||
| FLAC__uint64 *pu; /* unaligned pointer */ | |||||
| union { /* union needed to comply with C99 pointer aliasing rules */ | |||||
| FLAC__uint64 *pa; /* aligned pointer */ | |||||
| void *pv; /* aligned pointer alias */ | |||||
| } u; | |||||
| FLAC__ASSERT(elements > 0); | |||||
| FLAC__ASSERT(0 != unaligned_pointer); | |||||
| FLAC__ASSERT(0 != aligned_pointer); | |||||
| FLAC__ASSERT(unaligned_pointer != aligned_pointer); | |||||
| if((size_t)elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ | |||||
| return false; | |||||
| pu = (FLAC__uint64*)FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); | |||||
| if(0 == pu) { | |||||
| return false; | |||||
| } | |||||
| else { | |||||
| if(*unaligned_pointer != 0) | |||||
| free(*unaligned_pointer); | |||||
| *unaligned_pointer = pu; | |||||
| *aligned_pointer = u.pa; | |||||
| return true; | |||||
| } | |||||
| } | |||||
| FLAC__bool FLAC__memory_alloc_aligned_unsigned_array(unsigned elements, unsigned **unaligned_pointer, unsigned **aligned_pointer) | |||||
| { | |||||
| unsigned *pu; /* unaligned pointer */ | |||||
| union { /* union needed to comply with C99 pointer aliasing rules */ | |||||
| unsigned *pa; /* aligned pointer */ | |||||
| void *pv; /* aligned pointer alias */ | |||||
| } u; | |||||
| FLAC__ASSERT(elements > 0); | |||||
| FLAC__ASSERT(0 != unaligned_pointer); | |||||
| FLAC__ASSERT(0 != aligned_pointer); | |||||
| FLAC__ASSERT(unaligned_pointer != aligned_pointer); | |||||
| if((size_t)elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ | |||||
| return false; | |||||
| pu = (unsigned*)FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); | |||||
| if(0 == pu) { | |||||
| return false; | |||||
| } | |||||
| else { | |||||
| if(*unaligned_pointer != 0) | |||||
| free(*unaligned_pointer); | |||||
| *unaligned_pointer = pu; | |||||
| *aligned_pointer = u.pa; | |||||
| return true; | |||||
| } | |||||
| } | |||||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||||
| FLAC__bool FLAC__memory_alloc_aligned_real_array(unsigned elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer) | |||||
| { | |||||
| FLAC__real *pu; /* unaligned pointer */ | |||||
| union { /* union needed to comply with C99 pointer aliasing rules */ | |||||
| FLAC__real *pa; /* aligned pointer */ | |||||
| void *pv; /* aligned pointer alias */ | |||||
| } u; | |||||
| FLAC__ASSERT(elements > 0); | |||||
| FLAC__ASSERT(0 != unaligned_pointer); | |||||
| FLAC__ASSERT(0 != aligned_pointer); | |||||
| FLAC__ASSERT(unaligned_pointer != aligned_pointer); | |||||
| if((size_t)elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ | |||||
| return false; | |||||
| pu = (FLAC__real*)FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); | |||||
| if(0 == pu) { | |||||
| return false; | |||||
| } | |||||
| else { | |||||
| if(*unaligned_pointer != 0) | |||||
| free(*unaligned_pointer); | |||||
| *unaligned_pointer = pu; | |||||
| *aligned_pointer = u.pa; | |||||
| return true; | |||||
| } | |||||
| } | |||||
| #endif | |||||
| #endif | |||||
| @@ -0,0 +1,559 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 "juce_FlacHeader.h" | |||||
| #if JUCE_USE_FLAC | |||||
| #if HAVE_CONFIG_H | |||||
| # include <config.h> | |||||
| #endif | |||||
| #include <stdio.h> | |||||
| #include <string.h> /* for strlen() */ | |||||
| #include "include/private/stream_encoder_framing.h" | |||||
| #include "include/private/crc.h" | |||||
| #include "../assert.h" | |||||
| #ifdef max | |||||
| #undef max | |||||
| #endif | |||||
| #define max(x,y) ((x)>(y)?(x):(y)) | |||||
| static FLAC__bool add_entropy_coding_method_(FLAC__BitWriter *bw, const FLAC__EntropyCodingMethod *method); | |||||
| static FLAC__bool add_residual_partitioned_rice_(FLAC__BitWriter *bw, const FLAC__int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned raw_bits[], const unsigned partition_order, const FLAC__bool is_extended); | |||||
| FLAC__bool FLAC__add_metadata_block(const FLAC__StreamMetadata *metadata, FLAC__BitWriter *bw) | |||||
| { | |||||
| unsigned i, j; | |||||
| const unsigned vendor_string_length = (unsigned)strlen(FLAC__VENDOR_STRING); | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->is_last, FLAC__STREAM_METADATA_IS_LAST_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->type, FLAC__STREAM_METADATA_TYPE_LEN)) | |||||
| return false; | |||||
| /* | |||||
| * First, for VORBIS_COMMENTs, adjust the length to reflect our vendor string | |||||
| */ | |||||
| i = metadata->length; | |||||
| if(metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT) { | |||||
| FLAC__ASSERT(metadata->data.vorbis_comment.vendor_string.length == 0 || 0 != metadata->data.vorbis_comment.vendor_string.entry); | |||||
| i -= metadata->data.vorbis_comment.vendor_string.length; | |||||
| i += vendor_string_length; | |||||
| } | |||||
| FLAC__ASSERT(i < (1u << FLAC__STREAM_METADATA_LENGTH_LEN)); | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, i, FLAC__STREAM_METADATA_LENGTH_LEN)) | |||||
| return false; | |||||
| switch(metadata->type) { | |||||
| case FLAC__METADATA_TYPE_STREAMINFO: | |||||
| FLAC__ASSERT(metadata->data.stream_info.min_blocksize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN)); | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.min_blocksize, FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN)) | |||||
| return false; | |||||
| FLAC__ASSERT(metadata->data.stream_info.max_blocksize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN)); | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.max_blocksize, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN)) | |||||
| return false; | |||||
| FLAC__ASSERT(metadata->data.stream_info.min_framesize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN)); | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.min_framesize, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN)) | |||||
| return false; | |||||
| FLAC__ASSERT(metadata->data.stream_info.max_framesize < (1u << FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN)); | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.max_framesize, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN)) | |||||
| return false; | |||||
| FLAC__ASSERT(FLAC__format_sample_rate_is_valid(metadata->data.stream_info.sample_rate)); | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.sample_rate, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN)) | |||||
| return false; | |||||
| FLAC__ASSERT(metadata->data.stream_info.channels > 0); | |||||
| FLAC__ASSERT(metadata->data.stream_info.channels <= (1u << FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN)); | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.channels-1, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN)) | |||||
| return false; | |||||
| FLAC__ASSERT(metadata->data.stream_info.bits_per_sample > 0); | |||||
| FLAC__ASSERT(metadata->data.stream_info.bits_per_sample <= (1u << FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN)); | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.stream_info.bits_per_sample-1, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.stream_info.md5sum, 16)) | |||||
| return false; | |||||
| break; | |||||
| case FLAC__METADATA_TYPE_PADDING: | |||||
| if(!FLAC__bitwriter_write_zeroes(bw, metadata->length * 8)) | |||||
| return false; | |||||
| break; | |||||
| case FLAC__METADATA_TYPE_APPLICATION: | |||||
| if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.application.data, metadata->length - (FLAC__STREAM_METADATA_APPLICATION_ID_LEN / 8))) | |||||
| return false; | |||||
| break; | |||||
| case FLAC__METADATA_TYPE_SEEKTABLE: | |||||
| for(i = 0; i < metadata->data.seek_table.num_points; i++) { | |||||
| if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.seek_table.points[i].sample_number, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.seek_table.points[i].stream_offset, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.seek_table.points[i].frame_samples, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN)) | |||||
| return false; | |||||
| } | |||||
| break; | |||||
| case FLAC__METADATA_TYPE_VORBIS_COMMENT: | |||||
| if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, vendor_string_length)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)FLAC__VENDOR_STRING, vendor_string_length)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, metadata->data.vorbis_comment.num_comments)) | |||||
| return false; | |||||
| for(i = 0; i < metadata->data.vorbis_comment.num_comments; i++) { | |||||
| if(!FLAC__bitwriter_write_raw_uint32_little_endian(bw, metadata->data.vorbis_comment.comments[i].length)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.vorbis_comment.comments[i].entry, metadata->data.vorbis_comment.comments[i].length)) | |||||
| return false; | |||||
| } | |||||
| break; | |||||
| case FLAC__METADATA_TYPE_CUESHEET: | |||||
| FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0); | |||||
| if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)metadata->data.cue_sheet.media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint64(bw, metadata->data.cue_sheet.lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.cue_sheet.is_cd? 1 : 0, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.cue_sheet.num_tracks, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN)) | |||||
| return false; | |||||
| for(i = 0; i < metadata->data.cue_sheet.num_tracks; i++) { | |||||
| const FLAC__StreamMetadata_CueSheet_Track *track = metadata->data.cue_sheet.tracks + i; | |||||
| if(!FLAC__bitwriter_write_raw_uint64(bw, track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, track->number, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN)) | |||||
| return false; | |||||
| FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0); | |||||
| if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, track->type, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, track->pre_emphasis, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, track->num_indices, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN)) | |||||
| return false; | |||||
| for(j = 0; j < track->num_indices; j++) { | |||||
| const FLAC__StreamMetadata_CueSheet_Index *index = track->indices + j; | |||||
| if(!FLAC__bitwriter_write_raw_uint64(bw, index->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, index->number, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_zeroes(bw, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN)) | |||||
| return false; | |||||
| } | |||||
| } | |||||
| break; | |||||
| case FLAC__METADATA_TYPE_PICTURE: | |||||
| { | |||||
| size_t len; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.type, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN)) | |||||
| return false; | |||||
| len = strlen(metadata->data.picture.mime_type); | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, len, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_byte_block(bw, (const FLAC__byte*)metadata->data.picture.mime_type, len)) | |||||
| return false; | |||||
| len = strlen((const char *)metadata->data.picture.description); | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, len, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.picture.description, len)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.colors, FLAC__STREAM_METADATA_PICTURE_COLORS_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, metadata->data.picture.data_length, FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.picture.data, metadata->data.picture.data_length)) | |||||
| return false; | |||||
| } | |||||
| break; | |||||
| default: | |||||
| if(!FLAC__bitwriter_write_byte_block(bw, metadata->data.unknown.data, metadata->length)) | |||||
| return false; | |||||
| break; | |||||
| } | |||||
| FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw)); | |||||
| return true; | |||||
| } | |||||
| FLAC__bool FLAC__frame_add_header(const FLAC__FrameHeader *header, FLAC__BitWriter *bw) | |||||
| { | |||||
| unsigned u, blocksize_hint, sample_rate_hint; | |||||
| FLAC__byte crc; | |||||
| FLAC__ASSERT(FLAC__bitwriter_is_byte_aligned(bw)); | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__FRAME_HEADER_SYNC, FLAC__FRAME_HEADER_SYNC_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, 0, FLAC__FRAME_HEADER_RESERVED_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, (header->number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER)? 0 : 1, FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN)) | |||||
| return false; | |||||
| FLAC__ASSERT(header->blocksize > 0 && header->blocksize <= FLAC__MAX_BLOCK_SIZE); | |||||
| /* when this assertion holds true, any legal blocksize can be expressed in the frame header */ | |||||
| FLAC__ASSERT(FLAC__MAX_BLOCK_SIZE <= 65535u); | |||||
| blocksize_hint = 0; | |||||
| switch(header->blocksize) { | |||||
| case 192: u = 1; break; | |||||
| case 576: u = 2; break; | |||||
| case 1152: u = 3; break; | |||||
| case 2304: u = 4; break; | |||||
| case 4608: u = 5; break; | |||||
| case 256: u = 8; break; | |||||
| case 512: u = 9; break; | |||||
| case 1024: u = 10; break; | |||||
| case 2048: u = 11; break; | |||||
| case 4096: u = 12; break; | |||||
| case 8192: u = 13; break; | |||||
| case 16384: u = 14; break; | |||||
| case 32768: u = 15; break; | |||||
| default: | |||||
| if(header->blocksize <= 0x100) | |||||
| blocksize_hint = u = 6; | |||||
| else | |||||
| blocksize_hint = u = 7; | |||||
| break; | |||||
| } | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_BLOCK_SIZE_LEN)) | |||||
| return false; | |||||
| FLAC__ASSERT(FLAC__format_sample_rate_is_valid(header->sample_rate)); | |||||
| sample_rate_hint = 0; | |||||
| switch(header->sample_rate) { | |||||
| case 88200: u = 1; break; | |||||
| case 176400: u = 2; break; | |||||
| case 192000: u = 3; break; | |||||
| case 8000: u = 4; break; | |||||
| case 16000: u = 5; break; | |||||
| case 22050: u = 6; break; | |||||
| case 24000: u = 7; break; | |||||
| case 32000: u = 8; break; | |||||
| case 44100: u = 9; break; | |||||
| case 48000: u = 10; break; | |||||
| case 96000: u = 11; break; | |||||
| default: | |||||
| if(header->sample_rate <= 255000 && header->sample_rate % 1000 == 0) | |||||
| sample_rate_hint = u = 12; | |||||
| else if(header->sample_rate % 10 == 0) | |||||
| sample_rate_hint = u = 14; | |||||
| else if(header->sample_rate <= 0xffff) | |||||
| sample_rate_hint = u = 13; | |||||
| else | |||||
| u = 0; | |||||
| break; | |||||
| } | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_SAMPLE_RATE_LEN)) | |||||
| return false; | |||||
| FLAC__ASSERT(header->channels > 0 && header->channels <= (1u << FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN) && header->channels <= FLAC__MAX_CHANNELS); | |||||
| switch(header->channel_assignment) { | |||||
| case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: | |||||
| u = header->channels - 1; | |||||
| break; | |||||
| case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: | |||||
| FLAC__ASSERT(header->channels == 2); | |||||
| u = 8; | |||||
| break; | |||||
| case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: | |||||
| FLAC__ASSERT(header->channels == 2); | |||||
| u = 9; | |||||
| break; | |||||
| case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: | |||||
| FLAC__ASSERT(header->channels == 2); | |||||
| u = 10; | |||||
| break; | |||||
| default: | |||||
| FLAC__ASSERT(0); | |||||
| } | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN)) | |||||
| return false; | |||||
| FLAC__ASSERT(header->bits_per_sample > 0 && header->bits_per_sample <= (1u << FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN)); | |||||
| switch(header->bits_per_sample) { | |||||
| case 8 : u = 1; break; | |||||
| case 12: u = 2; break; | |||||
| case 16: u = 4; break; | |||||
| case 20: u = 5; break; | |||||
| case 24: u = 6; break; | |||||
| default: u = 0; break; | |||||
| } | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, u, FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, 0, FLAC__FRAME_HEADER_ZERO_PAD_LEN)) | |||||
| return false; | |||||
| if(header->number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER) { | |||||
| if(!FLAC__bitwriter_write_utf8_uint32(bw, header->number.frame_number)) | |||||
| return false; | |||||
| } | |||||
| else { | |||||
| if(!FLAC__bitwriter_write_utf8_uint64(bw, header->number.sample_number)) | |||||
| return false; | |||||
| } | |||||
| if(blocksize_hint) | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, header->blocksize-1, (blocksize_hint==6)? 8:16)) | |||||
| return false; | |||||
| switch(sample_rate_hint) { | |||||
| case 12: | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate / 1000, 8)) | |||||
| return false; | |||||
| break; | |||||
| case 13: | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate, 16)) | |||||
| return false; | |||||
| break; | |||||
| case 14: | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, header->sample_rate / 10, 16)) | |||||
| return false; | |||||
| break; | |||||
| } | |||||
| /* write the CRC */ | |||||
| if(!FLAC__bitwriter_get_write_crc8(bw, &crc)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, crc, FLAC__FRAME_HEADER_CRC_LEN)) | |||||
| return false; | |||||
| return true; | |||||
| } | |||||
| FLAC__bool FLAC__subframe_add_constant(const FLAC__Subframe_Constant *subframe, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw) | |||||
| { | |||||
| FLAC__bool ok; | |||||
| ok = | |||||
| FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN) && | |||||
| (wasted_bits? FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1) : true) && | |||||
| FLAC__bitwriter_write_raw_int32(bw, subframe->value, subframe_bps) | |||||
| ; | |||||
| return ok; | |||||
| } | |||||
| FLAC__bool FLAC__subframe_add_fixed(const FLAC__Subframe_Fixed *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw) | |||||
| { | |||||
| unsigned i; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK | (subframe->order<<1) | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN)) | |||||
| return false; | |||||
| if(wasted_bits) | |||||
| if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1)) | |||||
| return false; | |||||
| for(i = 0; i < subframe->order; i++) | |||||
| if(!FLAC__bitwriter_write_raw_int32(bw, subframe->warmup[i], subframe_bps)) | |||||
| return false; | |||||
| if(!add_entropy_coding_method_(bw, &subframe->entropy_coding_method)) | |||||
| return false; | |||||
| switch(subframe->entropy_coding_method.type) { | |||||
| case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: | |||||
| case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: | |||||
| if(!add_residual_partitioned_rice_( | |||||
| bw, | |||||
| subframe->residual, | |||||
| residual_samples, | |||||
| subframe->order, | |||||
| subframe->entropy_coding_method.data.partitioned_rice.contents->parameters, | |||||
| subframe->entropy_coding_method.data.partitioned_rice.contents->raw_bits, | |||||
| subframe->entropy_coding_method.data.partitioned_rice.order, | |||||
| /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 | |||||
| )) | |||||
| return false; | |||||
| break; | |||||
| default: | |||||
| FLAC__ASSERT(0); | |||||
| } | |||||
| return true; | |||||
| } | |||||
| FLAC__bool FLAC__subframe_add_lpc(const FLAC__Subframe_LPC *subframe, unsigned residual_samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw) | |||||
| { | |||||
| unsigned i; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK | ((subframe->order-1)<<1) | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN)) | |||||
| return false; | |||||
| if(wasted_bits) | |||||
| if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1)) | |||||
| return false; | |||||
| for(i = 0; i < subframe->order; i++) | |||||
| if(!FLAC__bitwriter_write_raw_int32(bw, subframe->warmup[i], subframe_bps)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, subframe->qlp_coeff_precision-1, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_int32(bw, subframe->quantization_level, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN)) | |||||
| return false; | |||||
| for(i = 0; i < subframe->order; i++) | |||||
| if(!FLAC__bitwriter_write_raw_int32(bw, subframe->qlp_coeff[i], subframe->qlp_coeff_precision)) | |||||
| return false; | |||||
| if(!add_entropy_coding_method_(bw, &subframe->entropy_coding_method)) | |||||
| return false; | |||||
| switch(subframe->entropy_coding_method.type) { | |||||
| case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: | |||||
| case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: | |||||
| if(!add_residual_partitioned_rice_( | |||||
| bw, | |||||
| subframe->residual, | |||||
| residual_samples, | |||||
| subframe->order, | |||||
| subframe->entropy_coding_method.data.partitioned_rice.contents->parameters, | |||||
| subframe->entropy_coding_method.data.partitioned_rice.contents->raw_bits, | |||||
| subframe->entropy_coding_method.data.partitioned_rice.order, | |||||
| /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 | |||||
| )) | |||||
| return false; | |||||
| break; | |||||
| default: | |||||
| FLAC__ASSERT(0); | |||||
| } | |||||
| return true; | |||||
| } | |||||
| FLAC__bool FLAC__subframe_add_verbatim(const FLAC__Subframe_Verbatim *subframe, unsigned samples, unsigned subframe_bps, unsigned wasted_bits, FLAC__BitWriter *bw) | |||||
| { | |||||
| unsigned i; | |||||
| const FLAC__int32 *signal = subframe->data; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK | (wasted_bits? 1:0), FLAC__SUBFRAME_ZERO_PAD_LEN + FLAC__SUBFRAME_TYPE_LEN + FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN)) | |||||
| return false; | |||||
| if(wasted_bits) | |||||
| if(!FLAC__bitwriter_write_unary_unsigned(bw, wasted_bits-1)) | |||||
| return false; | |||||
| for(i = 0; i < samples; i++) | |||||
| if(!FLAC__bitwriter_write_raw_int32(bw, signal[i], subframe_bps)) | |||||
| return false; | |||||
| return true; | |||||
| } | |||||
| FLAC__bool add_entropy_coding_method_(FLAC__BitWriter *bw, const FLAC__EntropyCodingMethod *method) | |||||
| { | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, method->type, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN)) | |||||
| return false; | |||||
| switch(method->type) { | |||||
| case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: | |||||
| case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, method->data.partitioned_rice.order, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN)) | |||||
| return false; | |||||
| break; | |||||
| default: | |||||
| FLAC__ASSERT(0); | |||||
| } | |||||
| return true; | |||||
| } | |||||
| FLAC__bool add_residual_partitioned_rice_(FLAC__BitWriter *bw, const FLAC__int32 residual[], const unsigned residual_samples, const unsigned predictor_order, const unsigned rice_parameters[], const unsigned raw_bits[], const unsigned partition_order, const FLAC__bool is_extended) | |||||
| { | |||||
| const unsigned plen = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; | |||||
| const unsigned pesc = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; | |||||
| if(partition_order == 0) { | |||||
| unsigned i; | |||||
| if(raw_bits[0] == 0) { | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, rice_parameters[0], plen)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_rice_signed_block(bw, residual, residual_samples, rice_parameters[0])) | |||||
| return false; | |||||
| } | |||||
| else { | |||||
| FLAC__ASSERT(rice_parameters[0] == 0); | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, pesc, plen)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, raw_bits[0], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN)) | |||||
| return false; | |||||
| for(i = 0; i < residual_samples; i++) { | |||||
| if(!FLAC__bitwriter_write_raw_int32(bw, residual[i], raw_bits[0])) | |||||
| return false; | |||||
| } | |||||
| } | |||||
| return true; | |||||
| } | |||||
| else { | |||||
| unsigned i, j, k = 0, k_last = 0; | |||||
| unsigned partition_samples; | |||||
| const unsigned default_partition_samples = (residual_samples+predictor_order) >> partition_order; | |||||
| for(i = 0; i < (1u<<partition_order); i++) { | |||||
| partition_samples = default_partition_samples; | |||||
| if(i == 0) | |||||
| partition_samples -= predictor_order; | |||||
| k += partition_samples; | |||||
| if(raw_bits[i] == 0) { | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, rice_parameters[i], plen)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_rice_signed_block(bw, residual+k_last, k-k_last, rice_parameters[i])) | |||||
| return false; | |||||
| } | |||||
| else { | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, pesc, plen)) | |||||
| return false; | |||||
| if(!FLAC__bitwriter_write_raw_uint32(bw, raw_bits[i], FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN)) | |||||
| return false; | |||||
| for(j = k_last; j < k; j++) { | |||||
| if(!FLAC__bitwriter_write_raw_int32(bw, residual[j], raw_bits[i])) | |||||
| return false; | |||||
| } | |||||
| } | |||||
| k_last = k; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,230 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 "juce_FlacHeader.h" | |||||
| #if JUCE_USE_FLAC | |||||
| #if HAVE_CONFIG_H | |||||
| # include <config.h> | |||||
| #endif | |||||
| #include <math.h> | |||||
| #include "../assert.h" | |||||
| #include "../format.h" | |||||
| #include "include/private/window.h" | |||||
| #ifndef FLAC__INTEGER_ONLY_LIBRARY | |||||
| #ifndef M_PI | |||||
| /* math.h in VC++ doesn't seem to have this (how Microsoft is that?) */ | |||||
| #define M_PI 3.14159265358979323846 | |||||
| #endif | |||||
| void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L) | |||||
| { | |||||
| const FLAC__int32 N = L - 1; | |||||
| FLAC__int32 n; | |||||
| if (L & 1) { | |||||
| for (n = 0; n <= N/2; n++) | |||||
| window[n] = 2.0f * n / (float)N; | |||||
| for (; n <= N; n++) | |||||
| window[n] = 2.0f - 2.0f * n / (float)N; | |||||
| } | |||||
| else { | |||||
| for (n = 0; n <= L/2-1; n++) | |||||
| window[n] = 2.0f * n / (float)N; | |||||
| for (; n <= N; n++) | |||||
| window[n] = 2.0f - 2.0f * (N-n) / (float)N; | |||||
| } | |||||
| } | |||||
| void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L) | |||||
| { | |||||
| const FLAC__int32 N = L - 1; | |||||
| FLAC__int32 n; | |||||
| for (n = 0; n < L; n++) | |||||
| window[n] = (FLAC__real)(0.62f - 0.48f * fabs((float)n/(float)N+0.5f) + 0.38f * cos(2.0f * M_PI * ((float)n/(float)N+0.5f))); | |||||
| } | |||||
| void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L) | |||||
| { | |||||
| const FLAC__int32 N = L - 1; | |||||
| FLAC__int32 n; | |||||
| for (n = 0; n < L; n++) | |||||
| window[n] = (FLAC__real)(0.42f - 0.5f * cos(2.0f * M_PI * n / N) + 0.08f * cos(4.0f * M_PI * n / N)); | |||||
| } | |||||
| /* 4-term -92dB side-lobe */ | |||||
| void FLAC__window_blackman_harris_4term_92db_sidelobe(FLAC__real *window, const FLAC__int32 L) | |||||
| { | |||||
| const FLAC__int32 N = L - 1; | |||||
| FLAC__int32 n; | |||||
| for (n = 0; n <= N; n++) | |||||
| window[n] = (FLAC__real)(0.35875f - 0.48829f * cos(2.0f * M_PI * n / N) + 0.14128f * cos(4.0f * M_PI * n / N) - 0.01168f * cos(6.0f * M_PI * n / N)); | |||||
| } | |||||
| void FLAC__window_connes(FLAC__real *window, const FLAC__int32 L) | |||||
| { | |||||
| const FLAC__int32 N = L - 1; | |||||
| const double N2 = (double)N / 2.; | |||||
| FLAC__int32 n; | |||||
| for (n = 0; n <= N; n++) { | |||||
| double k = ((double)n - N2) / N2; | |||||
| k = 1.0f - k * k; | |||||
| window[n] = (FLAC__real)(k * k); | |||||
| } | |||||
| } | |||||
| void FLAC__window_flattop(FLAC__real *window, const FLAC__int32 L) | |||||
| { | |||||
| const FLAC__int32 N = L - 1; | |||||
| FLAC__int32 n; | |||||
| for (n = 0; n < L; n++) | |||||
| window[n] = (FLAC__real)(1.0f - 1.93f * cos(2.0f * M_PI * n / N) + 1.29f * cos(4.0f * M_PI * n / N) - 0.388f * cos(6.0f * M_PI * n / N) + 0.0322f * cos(8.0f * M_PI * n / N)); | |||||
| } | |||||
| void FLAC__window_gauss(FLAC__real *window, const FLAC__int32 L, const FLAC__real stddev) | |||||
| { | |||||
| const FLAC__int32 N = L - 1; | |||||
| const double N2 = (double)N / 2.; | |||||
| FLAC__int32 n; | |||||
| for (n = 0; n <= N; n++) { | |||||
| const double k = ((double)n - N2) / (stddev * N2); | |||||
| window[n] = (FLAC__real)exp(-0.5f * k * k); | |||||
| } | |||||
| } | |||||
| void FLAC__window_hamming(FLAC__real *window, const FLAC__int32 L) | |||||
| { | |||||
| const FLAC__int32 N = L - 1; | |||||
| FLAC__int32 n; | |||||
| for (n = 0; n < L; n++) | |||||
| window[n] = (FLAC__real)(0.54f - 0.46f * cos(2.0f * M_PI * n / N)); | |||||
| } | |||||
| void FLAC__window_hann(FLAC__real *window, const FLAC__int32 L) | |||||
| { | |||||
| const FLAC__int32 N = L - 1; | |||||
| FLAC__int32 n; | |||||
| for (n = 0; n < L; n++) | |||||
| window[n] = (FLAC__real)(0.5f - 0.5f * cos(2.0f * M_PI * n / N)); | |||||
| } | |||||
| void FLAC__window_kaiser_bessel(FLAC__real *window, const FLAC__int32 L) | |||||
| { | |||||
| const FLAC__int32 N = L - 1; | |||||
| FLAC__int32 n; | |||||
| for (n = 0; n < L; n++) | |||||
| window[n] = (FLAC__real)(0.402f - 0.498f * cos(2.0f * M_PI * n / N) + 0.098f * cos(4.0f * M_PI * n / N) - 0.001f * cos(6.0f * M_PI * n / N)); | |||||
| } | |||||
| void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L) | |||||
| { | |||||
| const FLAC__int32 N = L - 1; | |||||
| FLAC__int32 n; | |||||
| for (n = 0; n < L; n++) | |||||
| window[n] = (FLAC__real)(0.3635819f - 0.4891775f*cos(2.0f*M_PI*n/N) + 0.1365995f*cos(4.0f*M_PI*n/N) - 0.0106411f*cos(6.0f*M_PI*n/N)); | |||||
| } | |||||
| void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L) | |||||
| { | |||||
| FLAC__int32 n; | |||||
| for (n = 0; n < L; n++) | |||||
| window[n] = 1.0f; | |||||
| } | |||||
| void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L) | |||||
| { | |||||
| FLAC__int32 n; | |||||
| if (L & 1) { | |||||
| for (n = 1; n <= L+1/2; n++) | |||||
| window[n-1] = 2.0f * n / ((float)L + 1.0f); | |||||
| for (; n <= L; n++) | |||||
| window[n-1] = - (float)(2 * (L - n + 1)) / ((float)L + 1.0f); | |||||
| } | |||||
| else { | |||||
| for (n = 1; n <= L/2; n++) | |||||
| window[n-1] = 2.0f * n / (float)L; | |||||
| for (; n <= L; n++) | |||||
| window[n-1] = ((float)(2 * (L - n)) + 1.0f) / (float)L; | |||||
| } | |||||
| } | |||||
| void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p) | |||||
| { | |||||
| if (p <= 0.0) | |||||
| FLAC__window_rectangle(window, L); | |||||
| else if (p >= 1.0) | |||||
| FLAC__window_hann(window, L); | |||||
| else { | |||||
| const FLAC__int32 Np = (FLAC__int32)(p / 2.0f * L) - 1; | |||||
| FLAC__int32 n; | |||||
| /* start with rectangle... */ | |||||
| FLAC__window_rectangle(window, L); | |||||
| /* ...replace ends with hann */ | |||||
| if (Np > 0) { | |||||
| for (n = 0; n <= Np; n++) { | |||||
| window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * n / Np)); | |||||
| window[L-Np-1+n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * (n+Np) / Np)); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L) | |||||
| { | |||||
| const FLAC__int32 N = L - 1; | |||||
| const double N2 = (double)N / 2.; | |||||
| FLAC__int32 n; | |||||
| for (n = 0; n <= N; n++) { | |||||
| const double k = ((double)n - N2) / N2; | |||||
| window[n] = (FLAC__real)(1.0f - k * k); | |||||
| } | |||||
| } | |||||
| #endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ | |||||
| #endif | |||||
| @@ -0,0 +1,80 @@ | |||||
| /* libFLAC - Free Lossless Audio Codec library | |||||
| * Copyright (C) 2000,2001,2002,2003,2004,2005,2006,2007 Josh Coalson | |||||
| * | |||||
| * 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 Xiph.org Foundation 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 FOUNDATION 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 FLAC__ORDINALS_H | |||||
| #define FLAC__ORDINALS_H | |||||
| #if !(defined(_MSC_VER) || defined(__BORLANDC__) || defined(__EMX__)) | |||||
| #include <inttypes.h> | |||||
| #endif | |||||
| typedef signed char FLAC__int8; | |||||
| typedef unsigned char FLAC__uint8; | |||||
| #if defined(_MSC_VER) || defined(__BORLANDC__) | |||||
| typedef __int16 FLAC__int16; | |||||
| typedef __int32 FLAC__int32; | |||||
| typedef __int64 FLAC__int64; | |||||
| typedef unsigned __int16 FLAC__uint16; | |||||
| typedef unsigned __int32 FLAC__uint32; | |||||
| typedef unsigned __int64 FLAC__uint64; | |||||
| #elif defined(__EMX__) | |||||
| typedef short FLAC__int16; | |||||
| typedef long FLAC__int32; | |||||
| typedef long long FLAC__int64; | |||||
| typedef unsigned short FLAC__uint16; | |||||
| typedef unsigned long FLAC__uint32; | |||||
| typedef unsigned long long FLAC__uint64; | |||||
| #else | |||||
| typedef int16_t FLAC__int16; | |||||
| typedef int32_t FLAC__int32; | |||||
| typedef int64_t FLAC__int64; | |||||
| typedef uint16_t FLAC__uint16; | |||||
| typedef uint32_t FLAC__uint32; | |||||
| typedef uint64_t FLAC__uint64; | |||||
| #endif | |||||
| typedef int FLAC__bool; | |||||
| typedef FLAC__uint8 FLAC__byte; | |||||
| #ifdef true | |||||
| #undef true | |||||
| #endif | |||||
| #ifdef false | |||||
| #undef false | |||||
| #endif | |||||
| #ifndef __cplusplus | |||||
| #define true 1 | |||||
| #define false 0 | |||||
| #endif | |||||
| #endif | |||||
| @@ -0,0 +1,813 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #include "../../core/juce_StandardHeader.h" | |||||
| BEGIN_JUCE_NAMESPACE | |||||
| #include "juce_AiffAudioFormat.h" | |||||
| #include "../../io/streams/juce_BufferedInputStream.h" | |||||
| #include "../../core/juce_PlatformUtilities.h" | |||||
| #include "../../text/juce_LocalisedStrings.h" | |||||
| #undef chunkName | |||||
| #define chunkName(a) (int)littleEndianInt(a) | |||||
| //============================================================================== | |||||
| #define aiffFormatName TRANS("AIFF file") | |||||
| static const tchar* const aiffExtensions[] = { T(".aiff"), T(".aif"), 0 }; | |||||
| //============================================================================== | |||||
| class AiffAudioFormatReader : public AudioFormatReader | |||||
| { | |||||
| public: | |||||
| int bytesPerFrame; | |||||
| int64 dataChunkStart; | |||||
| bool littleEndian; | |||||
| //============================================================================== | |||||
| AiffAudioFormatReader (InputStream* in) | |||||
| : AudioFormatReader (in, aiffFormatName) | |||||
| { | |||||
| if (input->readInt() == chunkName ("FORM")) | |||||
| { | |||||
| const int len = input->readIntBigEndian(); | |||||
| const int64 end = input->getPosition() + len; | |||||
| const int nextType = input->readInt(); | |||||
| if (nextType == chunkName ("AIFF") || nextType == chunkName ("AIFC")) | |||||
| { | |||||
| bool hasGotVer = false; | |||||
| bool hasGotData = false; | |||||
| bool hasGotType = false; | |||||
| while (input->getPosition() < end) | |||||
| { | |||||
| const int type = input->readInt(); | |||||
| const uint32 length = (uint32) input->readIntBigEndian(); | |||||
| const int64 chunkEnd = input->getPosition() + length; | |||||
| if (type == chunkName ("FVER")) | |||||
| { | |||||
| hasGotVer = true; | |||||
| const int ver = input->readIntBigEndian(); | |||||
| if (ver != 0 && ver != (int)0xa2805140) | |||||
| break; | |||||
| } | |||||
| else if (type == chunkName ("COMM")) | |||||
| { | |||||
| hasGotType = true; | |||||
| numChannels = (unsigned int)input->readShortBigEndian(); | |||||
| lengthInSamples = input->readIntBigEndian(); | |||||
| bitsPerSample = input->readShortBigEndian(); | |||||
| bytesPerFrame = (numChannels * bitsPerSample) >> 3; | |||||
| unsigned char sampleRateBytes[10]; | |||||
| input->read (sampleRateBytes, 10); | |||||
| const int byte0 = sampleRateBytes[0]; | |||||
| if ((byte0 & 0x80) != 0 | |||||
| || byte0 <= 0x3F || byte0 > 0x40 | |||||
| || (byte0 == 0x40 && sampleRateBytes[1] > 0x1C)) | |||||
| break; | |||||
| unsigned int sampRate = bigEndianInt ((char*) sampleRateBytes + 2); | |||||
| sampRate >>= (16414 - bigEndianShort ((char*) sampleRateBytes)); | |||||
| sampleRate = (int)sampRate; | |||||
| if (length <= 18) | |||||
| { | |||||
| // some types don't have a chunk large enough to include a compression | |||||
| // type, so assume it's just big-endian pcm | |||||
| littleEndian = false; | |||||
| } | |||||
| else | |||||
| { | |||||
| const int compType = input->readInt(); | |||||
| if (compType == chunkName ("NONE") || compType == chunkName ("twos")) | |||||
| { | |||||
| littleEndian = false; | |||||
| } | |||||
| else if (compType == chunkName ("sowt")) | |||||
| { | |||||
| littleEndian = true; | |||||
| } | |||||
| else | |||||
| { | |||||
| sampleRate = 0; | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| else if (type == chunkName ("SSND")) | |||||
| { | |||||
| hasGotData = true; | |||||
| const int offset = input->readIntBigEndian(); | |||||
| dataChunkStart = input->getPosition() + 4 + offset; | |||||
| lengthInSamples = (bytesPerFrame > 0) ? jmin (lengthInSamples, (int64) (length / bytesPerFrame)) : 0; | |||||
| } | |||||
| else if ((hasGotVer && hasGotData && hasGotType) | |||||
| || chunkEnd < input->getPosition() | |||||
| || input->isExhausted()) | |||||
| { | |||||
| break; | |||||
| } | |||||
| input->setPosition (chunkEnd); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| ~AiffAudioFormatReader() | |||||
| { | |||||
| } | |||||
| //============================================================================== | |||||
| bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, | |||||
| int64 startSampleInFile, int numSamples) | |||||
| { | |||||
| numSamples = (int) jmin ((int64) numSamples, lengthInSamples - startSampleInFile); | |||||
| if (numSamples <= 0) | |||||
| return true; | |||||
| input->setPosition (dataChunkStart + startSampleInFile * bytesPerFrame); | |||||
| const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3) | |||||
| char tempBuffer [tempBufSize]; | |||||
| while (numSamples > 0) | |||||
| { | |||||
| int* left = destSamples[0]; | |||||
| if (left != 0) | |||||
| left += startOffsetInDestBuffer; | |||||
| int* right = numDestChannels > 1 ? destSamples[1] : 0; | |||||
| if (right != 0) | |||||
| right += startOffsetInDestBuffer; | |||||
| const int numThisTime = jmin (tempBufSize / bytesPerFrame, numSamples); | |||||
| const int bytesRead = input->read (tempBuffer, numThisTime * bytesPerFrame); | |||||
| if (bytesRead < numThisTime * bytesPerFrame) | |||||
| zeromem (tempBuffer + bytesRead, numThisTime * bytesPerFrame - bytesRead); | |||||
| if (bitsPerSample == 16) | |||||
| { | |||||
| if (littleEndian) | |||||
| { | |||||
| const short* src = (const short*) tempBuffer; | |||||
| if (numChannels > 1) | |||||
| { | |||||
| if (left == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *right++ = (int) swapIfBigEndian ((unsigned short) *src++) << 16; | |||||
| ++src; | |||||
| } | |||||
| } | |||||
| else if (right == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| ++src; | |||||
| *left++ = (int) swapIfBigEndian ((unsigned short) *src++) << 16; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *left++ = (int) swapIfBigEndian ((unsigned short) *src++) << 16; | |||||
| *right++ = (int) swapIfBigEndian ((unsigned short) *src++) << 16; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *left++ = (int) swapIfBigEndian ((unsigned short) *src++) << 16; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| const char* src = (const char*) tempBuffer; | |||||
| if (numChannels > 1) | |||||
| { | |||||
| if (left == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *right++ = bigEndianShort (src) << 16; | |||||
| src += 4; | |||||
| } | |||||
| } | |||||
| else if (right == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| src += 2; | |||||
| *left++ = bigEndianShort (src) << 16; | |||||
| src += 2; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *left++ = bigEndianShort (src) << 16; | |||||
| src += 2; | |||||
| *right++ = bigEndianShort (src) << 16; | |||||
| src += 2; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *left++ = bigEndianShort (src) << 16; | |||||
| src += 2; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| else if (bitsPerSample == 24) | |||||
| { | |||||
| const char* src = (const char*)tempBuffer; | |||||
| if (littleEndian) | |||||
| { | |||||
| if (numChannels > 1) | |||||
| { | |||||
| if (left == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *right++ = littleEndian24Bit (src) << 8; | |||||
| src += 6; | |||||
| } | |||||
| } | |||||
| else if (right == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| src += 3; | |||||
| *left++ = littleEndian24Bit (src) << 8; | |||||
| src += 3; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *left++ = littleEndian24Bit (src) << 8; | |||||
| src += 3; | |||||
| *right++ = littleEndian24Bit (src) << 8; | |||||
| src += 3; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *left++ = littleEndian24Bit (src) << 8; | |||||
| src += 3; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| if (numChannels > 1) | |||||
| { | |||||
| if (left == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *right++ = bigEndian24Bit (src) << 8; | |||||
| src += 6; | |||||
| } | |||||
| } | |||||
| else if (right == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| src += 3; | |||||
| *left++ = bigEndian24Bit (src) << 8; | |||||
| src += 3; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *left++ = bigEndian24Bit (src) << 8; | |||||
| src += 3; | |||||
| *right++ = bigEndian24Bit (src) << 8; | |||||
| src += 3; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *left++ = bigEndian24Bit (src) << 8; | |||||
| src += 3; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| else if (bitsPerSample == 32) | |||||
| { | |||||
| const unsigned int* src = (const unsigned int*) tempBuffer; | |||||
| unsigned int* l = (unsigned int*) left; | |||||
| unsigned int* r = (unsigned int*) right; | |||||
| if (littleEndian) | |||||
| { | |||||
| if (numChannels > 1) | |||||
| { | |||||
| if (l == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| ++src; | |||||
| *r++ = swapIfBigEndian (*src++); | |||||
| } | |||||
| } | |||||
| else if (r == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *l++ = swapIfBigEndian (*src++); | |||||
| ++src; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *l++ = swapIfBigEndian (*src++); | |||||
| *r++ = swapIfBigEndian (*src++); | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *l++ = swapIfBigEndian (*src++); | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| if (numChannels > 1) | |||||
| { | |||||
| if (l == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| ++src; | |||||
| *r++ = swapIfLittleEndian (*src++); | |||||
| } | |||||
| } | |||||
| else if (r == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *l++ = swapIfLittleEndian (*src++); | |||||
| ++src; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *l++ = swapIfLittleEndian (*src++); | |||||
| *r++ = swapIfLittleEndian (*src++); | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *l++ = swapIfLittleEndian (*src++); | |||||
| } | |||||
| } | |||||
| } | |||||
| left = (int*) l; | |||||
| right = (int*) r; | |||||
| } | |||||
| else if (bitsPerSample == 8) | |||||
| { | |||||
| const char* src = (const char*) tempBuffer; | |||||
| if (numChannels > 1) | |||||
| { | |||||
| if (left == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *right++ = ((int) *src++) << 24; | |||||
| ++src; | |||||
| } | |||||
| } | |||||
| else if (right == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| ++src; | |||||
| *left++ = ((int) *src++) << 24; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *left++ = ((int) *src++) << 24; | |||||
| *right++ = ((int) *src++) << 24; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *left++ = ((int) *src++) << 24; | |||||
| } | |||||
| } | |||||
| } | |||||
| startOffsetInDestBuffer += numThisTime; | |||||
| numSamples -= numThisTime; | |||||
| } | |||||
| if (numSamples > 0) | |||||
| { | |||||
| for (int i = numDestChannels; --i >= 0;) | |||||
| if (destSamples[i] != 0) | |||||
| zeromem (destSamples[i] + startOffsetInDestBuffer, | |||||
| sizeof (int) * numSamples); | |||||
| } | |||||
| return true; | |||||
| } | |||||
| juce_UseDebuggingNewOperator | |||||
| private: | |||||
| AiffAudioFormatReader (const AiffAudioFormatReader&); | |||||
| const AiffAudioFormatReader& operator= (const AiffAudioFormatReader&); | |||||
| }; | |||||
| //============================================================================== | |||||
| class AiffAudioFormatWriter : public AudioFormatWriter | |||||
| { | |||||
| MemoryBlock tempBlock; | |||||
| uint32 lengthInSamples, bytesWritten; | |||||
| int64 headerPosition; | |||||
| bool writeFailed; | |||||
| AiffAudioFormatWriter (const AiffAudioFormatWriter&); | |||||
| const AiffAudioFormatWriter& operator= (const AiffAudioFormatWriter&); | |||||
| void writeHeader() | |||||
| { | |||||
| const bool couldSeekOk = output->setPosition (headerPosition); | |||||
| (void) couldSeekOk; | |||||
| // if this fails, you've given it an output stream that can't seek! It needs | |||||
| // to be able to seek back to write the header | |||||
| jassert (couldSeekOk); | |||||
| const int headerLen = 54; | |||||
| int audioBytes = lengthInSamples * ((bitsPerSample * numChannels) / 8); | |||||
| audioBytes += (audioBytes & 1); | |||||
| output->writeInt (chunkName ("FORM")); | |||||
| output->writeIntBigEndian (headerLen + audioBytes - 8); | |||||
| output->writeInt (chunkName ("AIFF")); | |||||
| output->writeInt (chunkName ("COMM")); | |||||
| output->writeIntBigEndian (18); | |||||
| output->writeShortBigEndian ((short) numChannels); | |||||
| output->writeIntBigEndian (lengthInSamples); | |||||
| output->writeShortBigEndian ((short) bitsPerSample); | |||||
| uint8 sampleRateBytes[10]; | |||||
| zeromem (sampleRateBytes, 10); | |||||
| if (sampleRate <= 1) | |||||
| { | |||||
| sampleRateBytes[0] = 0x3f; | |||||
| sampleRateBytes[1] = 0xff; | |||||
| sampleRateBytes[2] = 0x80; | |||||
| } | |||||
| else | |||||
| { | |||||
| int mask = 0x40000000; | |||||
| sampleRateBytes[0] = 0x40; | |||||
| if (sampleRate >= mask) | |||||
| { | |||||
| jassertfalse | |||||
| sampleRateBytes[1] = 0x1d; | |||||
| } | |||||
| else | |||||
| { | |||||
| int n = (int) sampleRate; | |||||
| int i; | |||||
| for (i = 0; i <= 32 ; ++i) | |||||
| { | |||||
| if ((n & mask) != 0) | |||||
| break; | |||||
| mask >>= 1; | |||||
| } | |||||
| n = n << (i + 1); | |||||
| sampleRateBytes[1] = (uint8) (29 - i); | |||||
| sampleRateBytes[2] = (uint8) ((n >> 24) & 0xff); | |||||
| sampleRateBytes[3] = (uint8) ((n >> 16) & 0xff); | |||||
| sampleRateBytes[4] = (uint8) ((n >> 8) & 0xff); | |||||
| sampleRateBytes[5] = (uint8) (n & 0xff); | |||||
| } | |||||
| } | |||||
| output->write (sampleRateBytes, 10); | |||||
| output->writeInt (chunkName ("SSND")); | |||||
| output->writeIntBigEndian (audioBytes + 8); | |||||
| output->writeInt (0); | |||||
| output->writeInt (0); | |||||
| jassert (output->getPosition() == headerLen); | |||||
| } | |||||
| public: | |||||
| //============================================================================== | |||||
| AiffAudioFormatWriter (OutputStream* out, | |||||
| const double sampleRate_, | |||||
| const unsigned int chans, | |||||
| const int bits) | |||||
| : AudioFormatWriter (out, | |||||
| aiffFormatName, | |||||
| sampleRate_, | |||||
| chans, | |||||
| bits), | |||||
| lengthInSamples (0), | |||||
| bytesWritten (0), | |||||
| writeFailed (false) | |||||
| { | |||||
| headerPosition = out->getPosition(); | |||||
| writeHeader(); | |||||
| } | |||||
| ~AiffAudioFormatWriter() | |||||
| { | |||||
| if ((bytesWritten & 1) != 0) | |||||
| output->writeByte (0); | |||||
| writeHeader(); | |||||
| } | |||||
| //============================================================================== | |||||
| bool write (const int** data, int numSamples) | |||||
| { | |||||
| if (writeFailed) | |||||
| return false; | |||||
| const int bytes = numChannels * numSamples * bitsPerSample / 8; | |||||
| tempBlock.ensureSize (bytes, false); | |||||
| char* buffer = (char*) tempBlock.getData(); | |||||
| const int* left = data[0]; | |||||
| const int* right = data[1]; | |||||
| if (right == 0) | |||||
| right = left; | |||||
| if (bitsPerSample == 16) | |||||
| { | |||||
| short* b = (short*) buffer; | |||||
| if (numChannels > 1) | |||||
| { | |||||
| for (int i = numSamples; --i >= 0;) | |||||
| { | |||||
| *b++ = (short) swapIfLittleEndian ((unsigned short) (*left++ >> 16)); | |||||
| *b++ = (short) swapIfLittleEndian ((unsigned short) (*right++ >> 16)); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numSamples; --i >= 0;) | |||||
| { | |||||
| *b++ = (short) swapIfLittleEndian ((unsigned short) (*left++ >> 16)); | |||||
| } | |||||
| } | |||||
| } | |||||
| else if (bitsPerSample == 24) | |||||
| { | |||||
| char* b = (char*) buffer; | |||||
| if (numChannels > 1) | |||||
| { | |||||
| for (int i = numSamples; --i >= 0;) | |||||
| { | |||||
| bigEndian24BitToChars (*left++ >> 8, b); | |||||
| b += 3; | |||||
| bigEndian24BitToChars (*right++ >> 8, b); | |||||
| b += 3; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numSamples; --i >= 0;) | |||||
| { | |||||
| bigEndian24BitToChars (*left++ >> 8, b); | |||||
| b += 3; | |||||
| } | |||||
| } | |||||
| } | |||||
| else if (bitsPerSample == 32) | |||||
| { | |||||
| unsigned int* b = (unsigned int*) buffer; | |||||
| if (numChannels > 1) | |||||
| { | |||||
| for (int i = numSamples; --i >= 0;) | |||||
| { | |||||
| *b++ = swapIfLittleEndian ((unsigned int) *left++); | |||||
| *b++ = swapIfLittleEndian ((unsigned int) *right++); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numSamples; --i >= 0;) | |||||
| { | |||||
| *b++ = swapIfLittleEndian ((unsigned int) *left++); | |||||
| } | |||||
| } | |||||
| } | |||||
| else if (bitsPerSample == 8) | |||||
| { | |||||
| char* b = (char*)buffer; | |||||
| if (numChannels > 1) | |||||
| { | |||||
| for (int i = numSamples; --i >= 0;) | |||||
| { | |||||
| *b++ = (char) (*left++ >> 24); | |||||
| *b++ = (char) (*right++ >> 24); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numSamples; --i >= 0;) | |||||
| { | |||||
| *b++ = (char) (*left++ >> 24); | |||||
| } | |||||
| } | |||||
| } | |||||
| if (bytesWritten + bytes >= (uint32) 0xfff00000 | |||||
| || ! output->write (buffer, bytes)) | |||||
| { | |||||
| // failed to write to disk, so let's try writing the header. | |||||
| // If it's just run out of disk space, then if it does manage | |||||
| // to write the header, we'll still have a useable file.. | |||||
| writeHeader(); | |||||
| writeFailed = true; | |||||
| return false; | |||||
| } | |||||
| else | |||||
| { | |||||
| bytesWritten += bytes; | |||||
| lengthInSamples += numSamples; | |||||
| return true; | |||||
| } | |||||
| } | |||||
| juce_UseDebuggingNewOperator | |||||
| }; | |||||
| //============================================================================== | |||||
| AiffAudioFormat::AiffAudioFormat() | |||||
| : AudioFormat (aiffFormatName, (const tchar**) aiffExtensions) | |||||
| { | |||||
| } | |||||
| AiffAudioFormat::~AiffAudioFormat() | |||||
| { | |||||
| } | |||||
| const Array <int> AiffAudioFormat::getPossibleSampleRates() | |||||
| { | |||||
| const int rates[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 0 }; | |||||
| return Array <int> (rates); | |||||
| } | |||||
| const Array <int> AiffAudioFormat::getPossibleBitDepths() | |||||
| { | |||||
| const int depths[] = { 8, 16, 24, 0 }; | |||||
| return Array <int> (depths); | |||||
| } | |||||
| bool AiffAudioFormat::canDoStereo() | |||||
| { | |||||
| return true; | |||||
| } | |||||
| bool AiffAudioFormat::canDoMono() | |||||
| { | |||||
| return true; | |||||
| } | |||||
| #if JUCE_MAC | |||||
| bool AiffAudioFormat::canHandleFile (const File& f) | |||||
| { | |||||
| if (AudioFormat::canHandleFile (f)) | |||||
| return true; | |||||
| const OSType type = PlatformUtilities::getTypeOfFile (f.getFullPathName()); | |||||
| return type == 'AIFF' || type == 'AIFC' | |||||
| || type == 'aiff' || type == 'aifc'; | |||||
| } | |||||
| #endif | |||||
| AudioFormatReader* AiffAudioFormat::createReaderFor (InputStream* sourceStream, | |||||
| const bool deleteStreamIfOpeningFails) | |||||
| { | |||||
| AiffAudioFormatReader* w = new AiffAudioFormatReader (sourceStream); | |||||
| if (w->sampleRate == 0) | |||||
| { | |||||
| if (! deleteStreamIfOpeningFails) | |||||
| w->input = 0; | |||||
| deleteAndZero (w); | |||||
| } | |||||
| return w; | |||||
| } | |||||
| AudioFormatWriter* AiffAudioFormat::createWriterFor (OutputStream* out, | |||||
| double sampleRate, | |||||
| unsigned int chans, | |||||
| int bitsPerSample, | |||||
| const StringPairArray& /*metadataValues*/, | |||||
| int /*qualityOptionIndex*/) | |||||
| { | |||||
| if (getPossibleBitDepths().contains (bitsPerSample)) | |||||
| { | |||||
| return new AiffAudioFormatWriter (out, | |||||
| sampleRate, | |||||
| chans, | |||||
| bitsPerSample); | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| END_JUCE_NAMESPACE | |||||
| @@ -0,0 +1,74 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #ifndef __JUCE_AIFFAUDIOFORMAT_JUCEHEADER__ | |||||
| #define __JUCE_AIFFAUDIOFORMAT_JUCEHEADER__ | |||||
| #include "juce_AudioFormat.h" | |||||
| //============================================================================== | |||||
| /** | |||||
| Reads and Writes AIFF format audio files. | |||||
| @see AudioFormat | |||||
| */ | |||||
| class JUCE_API AiffAudioFormat : public AudioFormat | |||||
| { | |||||
| public: | |||||
| //============================================================================== | |||||
| /** Creates an format object. */ | |||||
| AiffAudioFormat(); | |||||
| /** Destructor. */ | |||||
| ~AiffAudioFormat(); | |||||
| //============================================================================== | |||||
| const Array <int> getPossibleSampleRates(); | |||||
| const Array <int> getPossibleBitDepths(); | |||||
| bool canDoStereo(); | |||||
| bool canDoMono(); | |||||
| #if JUCE_MAC | |||||
| bool canHandleFile (const File& fileToTest); | |||||
| #endif | |||||
| //============================================================================== | |||||
| AudioFormatReader* createReaderFor (InputStream* sourceStream, | |||||
| const bool deleteStreamIfOpeningFails); | |||||
| AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, | |||||
| double sampleRateToUse, | |||||
| unsigned int numberOfChannels, | |||||
| int bitsPerSample, | |||||
| const StringPairArray& metadataValues, | |||||
| int qualityOptionIndex); | |||||
| //============================================================================== | |||||
| juce_UseDebuggingNewOperator | |||||
| }; | |||||
| #endif // __JUCE_AIFFAUDIOFORMAT_JUCEHEADER__ | |||||
| @@ -0,0 +1,107 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #ifndef __JUCE_AUDIOCDBURNER_JUCEHEADER__ | |||||
| #define __JUCE_AUDIOCDBURNER_JUCEHEADER__ | |||||
| #include "juce_AudioFormatReader.h" | |||||
| #include "../audio_sources/juce_AudioSource.h" | |||||
| //============================================================================== | |||||
| /** | |||||
| */ | |||||
| class AudioCDBurner | |||||
| { | |||||
| public: | |||||
| //============================================================================== | |||||
| /** Returns a list of available optical drives. | |||||
| Use openDevice() to open one of the items from this list. | |||||
| */ | |||||
| static const StringArray findAvailableDevices(); | |||||
| /** Tries to open one of the optical drives. | |||||
| The deviceIndex is an index into the array returned by findAvailableDevices(). | |||||
| */ | |||||
| static AudioCDBurner* openDevice (const int deviceIndex); | |||||
| /** Destructor. */ | |||||
| ~AudioCDBurner(); | |||||
| //============================================================================== | |||||
| /** Returns true if there's a writable disk in the drive. | |||||
| */ | |||||
| bool isDiskPresent() const; | |||||
| /** Returns the number of free blocks on the disk. | |||||
| There are 75 blocks per second, at 44100Hz. | |||||
| */ | |||||
| int getNumAvailableAudioBlocks() const; | |||||
| /** Adds a track to be written. | |||||
| The source passed-in here will be kept by this object, and it will | |||||
| be used and deleted at some point in the future, either during the | |||||
| burn() method or when this AudioCDBurner object is deleted. Your caller | |||||
| method shouldn't keep a reference to it or use it again after passing | |||||
| it in here. | |||||
| */ | |||||
| bool addAudioTrack (AudioSource* source, int numSamples); | |||||
| /** | |||||
| Return true to cancel the current burn operation | |||||
| */ | |||||
| class BurnProgressListener | |||||
| { | |||||
| public: | |||||
| BurnProgressListener() throw() {} | |||||
| virtual ~BurnProgressListener() {} | |||||
| /** Called at intervals to report on the progress of the AudioCDBurner. | |||||
| To cancel the burn, return true from this. | |||||
| */ | |||||
| virtual bool audioCDBurnProgress (float proportionComplete) = 0; | |||||
| }; | |||||
| const String burn (BurnProgressListener* listener, | |||||
| const bool ejectDiscAfterwards, | |||||
| const bool peformFakeBurnForTesting); | |||||
| //============================================================================== | |||||
| juce_UseDebuggingNewOperator | |||||
| private: | |||||
| AudioCDBurner (const int deviceIndex); | |||||
| void* internal; | |||||
| }; | |||||
| #endif // __JUCE_AUDIOCDBURNER_JUCEHEADER__ | |||||
| @@ -0,0 +1,245 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #include "../../core/juce_StandardHeader.h" | |||||
| BEGIN_JUCE_NAMESPACE | |||||
| #if JUCE_MAC | |||||
| //============================================================================== | |||||
| // Mac version doesn't need any native code because it's all done with files.. | |||||
| // Windows + Linux versions are in the platform-dependent code sections. | |||||
| #include "juce_AudioCDReader.h" | |||||
| #include "juce_AiffAudioFormat.h" | |||||
| #include "../../io/files/juce_FileInputStream.h" | |||||
| #include "../../io/streams/juce_BufferedInputStream.h" | |||||
| static void findCDs (OwnedArray<File>& cds) | |||||
| { | |||||
| File volumes ("/Volumes"); | |||||
| volumes.findChildFiles (cds, File::findDirectories, false); | |||||
| for (int i = cds.size(); --i >= 0;) | |||||
| if (! cds[i]->getChildFile (".TOC.plist").exists()) | |||||
| cds.remove (i); | |||||
| } | |||||
| const StringArray AudioCDReader::getAvailableCDNames() | |||||
| { | |||||
| OwnedArray<File> cds; | |||||
| findCDs (cds); | |||||
| StringArray names; | |||||
| for (int i = 0; i < cds.size(); ++i) | |||||
| names.add (cds[i]->getFileName()); | |||||
| return names; | |||||
| } | |||||
| AudioCDReader* AudioCDReader::createReaderForCD (const int index) | |||||
| { | |||||
| OwnedArray<File> cds; | |||||
| findCDs (cds); | |||||
| if (cds[index] != 0) | |||||
| return new AudioCDReader (*cds[index]); | |||||
| else | |||||
| return 0; | |||||
| } | |||||
| AudioCDReader::AudioCDReader (const File& volume) | |||||
| : AudioFormatReader (0, "CD Audio"), | |||||
| volumeDir (volume), | |||||
| currentReaderTrack (-1), | |||||
| reader (0) | |||||
| { | |||||
| sampleRate = 44100.0; | |||||
| bitsPerSample = 16; | |||||
| numChannels = 2; | |||||
| usesFloatingPointData = false; | |||||
| refreshTrackLengths(); | |||||
| } | |||||
| AudioCDReader::~AudioCDReader() | |||||
| { | |||||
| if (reader != 0) | |||||
| delete reader; | |||||
| } | |||||
| static int getTrackNumber (const File& file) | |||||
| { | |||||
| return file.getFileName() | |||||
| .initialSectionContainingOnly (T("0123456789")) | |||||
| .getIntValue(); | |||||
| } | |||||
| int AudioCDReader::compareElements (const File* const first, const File* const second) throw() | |||||
| { | |||||
| const int firstTrack = getTrackNumber (*first); | |||||
| const int secondTrack = getTrackNumber (*second); | |||||
| jassert (firstTrack > 0 && secondTrack > 0); | |||||
| return firstTrack - secondTrack; | |||||
| } | |||||
| void AudioCDReader::refreshTrackLengths() | |||||
| { | |||||
| tracks.clear(); | |||||
| trackStartSamples.clear(); | |||||
| volumeDir.findChildFiles (tracks, File::findFiles | File::ignoreHiddenFiles, false, T("*.aiff")); | |||||
| tracks.sort (*this); | |||||
| AiffAudioFormat format; | |||||
| int sample = 0; | |||||
| for (int i = 0; i < tracks.size(); ++i) | |||||
| { | |||||
| trackStartSamples.add (sample); | |||||
| FileInputStream* const in = tracks[i]->createInputStream(); | |||||
| if (in != 0) | |||||
| { | |||||
| AudioFormatReader* const r = format.createReaderFor (in, true); | |||||
| if (r != 0) | |||||
| { | |||||
| sample += r->lengthInSamples; | |||||
| delete r; | |||||
| } | |||||
| } | |||||
| } | |||||
| trackStartSamples.add (sample); | |||||
| lengthInSamples = sample; | |||||
| } | |||||
| bool AudioCDReader::readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, | |||||
| int64 startSampleInFile, int numSamples) | |||||
| { | |||||
| while (numSamples > 0) | |||||
| { | |||||
| int track = -1; | |||||
| for (int i = 0; i < trackStartSamples.size() - 1; ++i) | |||||
| { | |||||
| if (startSampleInFile < trackStartSamples.getUnchecked (i + 1)) | |||||
| { | |||||
| track = i; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (track < 0) | |||||
| return false; | |||||
| if (track != currentReaderTrack) | |||||
| { | |||||
| deleteAndZero (reader); | |||||
| if (tracks [track] != 0) | |||||
| { | |||||
| FileInputStream* const in = tracks [track]->createInputStream(); | |||||
| if (in != 0) | |||||
| { | |||||
| BufferedInputStream* const bin = new BufferedInputStream (in, 65536, true); | |||||
| AiffAudioFormat format; | |||||
| reader = format.createReaderFor (bin, true); | |||||
| if (reader == 0) | |||||
| currentReaderTrack = -1; | |||||
| else | |||||
| currentReaderTrack = track; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (reader == 0) | |||||
| return false; | |||||
| const int startPos = (int) (startSampleInFile - trackStartSamples.getUnchecked (track)); | |||||
| const int numAvailable = (int) jmin ((int64) numSamples, reader->lengthInSamples - startPos); | |||||
| reader->readSamples (destSamples, numDestChannels, startOffsetInDestBuffer, startPos, numAvailable); | |||||
| numSamples -= numAvailable; | |||||
| startSampleInFile += numAvailable; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| bool AudioCDReader::isCDStillPresent() const | |||||
| { | |||||
| return volumeDir.exists(); | |||||
| } | |||||
| int AudioCDReader::getNumTracks() const | |||||
| { | |||||
| return tracks.size(); | |||||
| } | |||||
| int AudioCDReader::getPositionOfTrackStart (int trackNum) const | |||||
| { | |||||
| return trackStartSamples [trackNum]; | |||||
| } | |||||
| bool AudioCDReader::isTrackAudio (int trackNum) const | |||||
| { | |||||
| return tracks [trackNum] != 0; | |||||
| } | |||||
| void AudioCDReader::enableIndexScanning (bool b) | |||||
| { | |||||
| // any way to do this on a Mac?? | |||||
| } | |||||
| int AudioCDReader::getLastIndex() const | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| const Array <int> AudioCDReader::findIndexesInTrack (const int trackNumber) | |||||
| { | |||||
| return Array <int>(); | |||||
| } | |||||
| int AudioCDReader::getCDDBId() | |||||
| { | |||||
| return 0; //xxx | |||||
| } | |||||
| #endif | |||||
| END_JUCE_NAMESPACE | |||||
| @@ -0,0 +1,180 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #ifndef __JUCE_AUDIOCDREADER_JUCEHEADER__ | |||||
| #define __JUCE_AUDIOCDREADER_JUCEHEADER__ | |||||
| #include "juce_AudioFormatReader.h" | |||||
| #include "../../text/juce_StringArray.h" | |||||
| #if JUCE_MAC | |||||
| #include "../../io/files/juce_File.h" | |||||
| #endif | |||||
| //============================================================================== | |||||
| /** | |||||
| A type of AudioFormatReader that reads from an audio CD. | |||||
| One of these can be used to read a CD as if it's one big audio stream. Use the | |||||
| getPositionOfTrackStart() method to find where the individual tracks are | |||||
| within the stream. | |||||
| @see AudioFormatReader | |||||
| */ | |||||
| class JUCE_API AudioCDReader : public AudioFormatReader | |||||
| { | |||||
| public: | |||||
| //============================================================================== | |||||
| /** Returns a list of names of Audio CDs currently available for reading. | |||||
| If there's a CD drive but no CD in it, this might return an empty list, or | |||||
| possibly a device that can be opened but which has no tracks, depending | |||||
| on the platform. | |||||
| @see createReaderForCD | |||||
| */ | |||||
| static const StringArray getAvailableCDNames(); | |||||
| /** Tries to create an AudioFormatReader that can read from an Audio CD. | |||||
| @param index the index of one of the available CDs - use getAvailableCDNames() | |||||
| to find out how many there are. | |||||
| @returns a new AudioCDReader object, or 0 if it couldn't be created. The | |||||
| caller will be responsible for deleting the object returned. | |||||
| */ | |||||
| static AudioCDReader* createReaderForCD (const int index); | |||||
| //============================================================================== | |||||
| /** Destructor. */ | |||||
| ~AudioCDReader(); | |||||
| /** Implementation of the AudioFormatReader method. */ | |||||
| bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, | |||||
| int64 startSampleInFile, int numSamples); | |||||
| /** Checks whether the CD has been removed from the drive. | |||||
| */ | |||||
| bool isCDStillPresent() const; | |||||
| /** Returns the total number of tracks (audio + data). | |||||
| */ | |||||
| int getNumTracks() const; | |||||
| /** Finds the sample offset of the start of a track. | |||||
| @param trackNum the track number, where 0 is the first track. | |||||
| */ | |||||
| int getPositionOfTrackStart (int trackNum) const; | |||||
| /** Returns true if a given track is an audio track. | |||||
| @param trackNum the track number, where 0 is the first track. | |||||
| */ | |||||
| bool isTrackAudio (int trackNum) const; | |||||
| /** Refreshes the object's table of contents. | |||||
| If the disc has been ejected and a different one put in since this | |||||
| object was created, this will cause it to update its idea of how many tracks | |||||
| there are, etc. | |||||
| */ | |||||
| void refreshTrackLengths(); | |||||
| /** Enables scanning for indexes within tracks. | |||||
| @see getLastIndex | |||||
| */ | |||||
| void enableIndexScanning (bool enabled); | |||||
| /** Returns the index number found during the last read() call. | |||||
| Index scanning is turned off by default - turn it on with enableIndexScanning(). | |||||
| Then when the read() method is called, if it comes across an index within that | |||||
| block, the index number is stored and returned by this method. | |||||
| Some devices might not support indexes, of course. | |||||
| (If you don't know what CD indexes are, it's unlikely you'll ever need them). | |||||
| @see enableIndexScanning | |||||
| */ | |||||
| int getLastIndex() const; | |||||
| /** Scans a track to find the position of any indexes within it. | |||||
| @param trackNumber the track to look in, where 0 is the first track on the disc | |||||
| @returns an array of sample positions of any index points found (not including | |||||
| the index that marks the start of the track) | |||||
| */ | |||||
| const Array <int> findIndexesInTrack (const int trackNumber); | |||||
| /** Returns the CDDB id number for the CD. | |||||
| It's not a great way of identifying a disc, but it's traditional. | |||||
| */ | |||||
| int getCDDBId(); | |||||
| /** Tries to eject the disk. | |||||
| Of course this might not be possible, if some other process is using it. | |||||
| */ | |||||
| void ejectDisk(); | |||||
| //============================================================================== | |||||
| juce_UseDebuggingNewOperator | |||||
| private: | |||||
| #if JUCE_MAC | |||||
| File volumeDir; | |||||
| OwnedArray<File> tracks; | |||||
| Array <int> trackStartSamples; | |||||
| int currentReaderTrack; | |||||
| AudioFormatReader* reader; | |||||
| AudioCDReader (const File& volume); | |||||
| public: | |||||
| static int compareElements (const File* const, const File* const) throw(); | |||||
| private: | |||||
| #elif JUCE_WIN32 | |||||
| int numTracks; | |||||
| int trackStarts[100]; | |||||
| bool audioTracks [100]; | |||||
| void* handle; | |||||
| bool indexingEnabled; | |||||
| int lastIndex, firstFrameInBuffer, samplesInBuffer; | |||||
| MemoryBlock buffer; | |||||
| AudioCDReader (void* handle); | |||||
| int getIndexAt (int samplePos); | |||||
| #elif JUCE_LINUX | |||||
| AudioCDReader(); | |||||
| #endif | |||||
| AudioCDReader (const AudioCDReader&); | |||||
| const AudioCDReader& operator= (const AudioCDReader&); | |||||
| }; | |||||
| #endif // __JUCE_AUDIOCDREADER_JUCEHEADER__ | |||||
| @@ -0,0 +1,557 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #include "../../core/juce_StandardHeader.h" | |||||
| BEGIN_JUCE_NAMESPACE | |||||
| #include "juce_AudioFormat.h" | |||||
| #include "../dsp/juce_AudioSampleBuffer.h" | |||||
| //============================================================================== | |||||
| AudioFormatReader::AudioFormatReader (InputStream* const in, | |||||
| const String& formatName_) | |||||
| : sampleRate (0), | |||||
| bitsPerSample (0), | |||||
| lengthInSamples (0), | |||||
| numChannels (0), | |||||
| usesFloatingPointData (false), | |||||
| input (in), | |||||
| formatName (formatName_) | |||||
| { | |||||
| } | |||||
| AudioFormatReader::~AudioFormatReader() | |||||
| { | |||||
| delete input; | |||||
| } | |||||
| bool AudioFormatReader::read (int** destSamples, | |||||
| int numDestChannels, | |||||
| int64 startSampleInSource, | |||||
| int numSamplesToRead, | |||||
| const bool fillLeftoverChannelsWithCopies) | |||||
| { | |||||
| jassert (numDestChannels > 0); // you have to actually give this some channels to work with! | |||||
| int startOffsetInDestBuffer = 0; | |||||
| if (startSampleInSource < 0) | |||||
| { | |||||
| const int silence = (int) jmin (-startSampleInSource, (int64) numSamplesToRead); | |||||
| for (int i = numDestChannels; --i >= 0;) | |||||
| if (destSamples[i] != 0) | |||||
| zeromem (destSamples[i], sizeof (int) * silence); | |||||
| startOffsetInDestBuffer += silence; | |||||
| numSamplesToRead -= silence; | |||||
| startSampleInSource = 0; | |||||
| } | |||||
| if (numSamplesToRead <= 0) | |||||
| return true; | |||||
| if (! readSamples (destSamples, jmin (numChannels, numDestChannels), startOffsetInDestBuffer, | |||||
| startSampleInSource, numSamplesToRead)) | |||||
| return false; | |||||
| if (numDestChannels > (int) numChannels) | |||||
| { | |||||
| if (fillLeftoverChannelsWithCopies) | |||||
| { | |||||
| int* lastFullChannel = destSamples[0]; | |||||
| for (int i = numDestChannels; --i > 0;) | |||||
| { | |||||
| if (destSamples[i] != 0) | |||||
| { | |||||
| lastFullChannel = destSamples[i]; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (lastFullChannel != 0) | |||||
| for (int i = numChannels; i < numDestChannels; ++i) | |||||
| if (destSamples[i] != 0) | |||||
| memcpy (destSamples[i], lastFullChannel, sizeof (int) * numSamplesToRead); | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numChannels; i < numDestChannels; ++i) | |||||
| if (destSamples[i] != 0) | |||||
| zeromem (destSamples[i], sizeof (int) * numSamplesToRead); | |||||
| } | |||||
| } | |||||
| return true; | |||||
| } | |||||
| static void findMaxMin (const float* src, const int num, | |||||
| float& maxVal, float& minVal) | |||||
| { | |||||
| float mn = src[0]; | |||||
| float mx = mn; | |||||
| for (int i = 1; i < num; ++i) | |||||
| { | |||||
| const float s = src[i]; | |||||
| if (s > mx) | |||||
| mx = s; | |||||
| if (s < mn) | |||||
| mn = s; | |||||
| } | |||||
| maxVal = mx; | |||||
| minVal = mn; | |||||
| } | |||||
| void AudioFormatReader::readMaxLevels (int64 startSampleInFile, | |||||
| int64 numSamples, | |||||
| float& lowestLeft, float& highestLeft, | |||||
| float& lowestRight, float& highestRight) | |||||
| { | |||||
| if (numSamples <= 0) | |||||
| { | |||||
| lowestLeft = 0; | |||||
| lowestRight = 0; | |||||
| highestLeft = 0; | |||||
| highestRight = 0; | |||||
| return; | |||||
| } | |||||
| const int bufferSize = (int) jmin (numSamples, (int64) 4096); | |||||
| MemoryBlock tempSpace (bufferSize * sizeof (int) * 2 + 64); | |||||
| int* tempBuffer[3]; | |||||
| tempBuffer[0] = (int*) tempSpace.getData(); | |||||
| tempBuffer[1] = ((int*) tempSpace.getData()) + bufferSize; | |||||
| tempBuffer[2] = 0; | |||||
| if (usesFloatingPointData) | |||||
| { | |||||
| float lmin = 1.0e6; | |||||
| float lmax = -lmin; | |||||
| float rmin = lmin; | |||||
| float rmax = lmax; | |||||
| while (numSamples > 0) | |||||
| { | |||||
| const int numToDo = (int) jmin (numSamples, (int64) bufferSize); | |||||
| read ((int**) tempBuffer, 2, startSampleInFile, numToDo, false); | |||||
| numSamples -= numToDo; | |||||
| float bufmin, bufmax; | |||||
| findMaxMin ((float*) tempBuffer[0], numToDo, bufmax, bufmin); | |||||
| lmin = jmin (lmin, bufmin); | |||||
| lmax = jmax (lmax, bufmax); | |||||
| if (numChannels > 1) | |||||
| { | |||||
| findMaxMin ((float*) tempBuffer[1], numToDo, bufmax, bufmin); | |||||
| rmin = jmin (rmin, bufmin); | |||||
| rmax = jmax (rmax, bufmax); | |||||
| } | |||||
| } | |||||
| if (numChannels <= 1) | |||||
| { | |||||
| rmax = lmax; | |||||
| rmin = lmin; | |||||
| } | |||||
| lowestLeft = lmin; | |||||
| highestLeft = lmax; | |||||
| lowestRight = rmin; | |||||
| highestRight = rmax; | |||||
| } | |||||
| else | |||||
| { | |||||
| int lmax = INT_MIN; | |||||
| int lmin = INT_MAX; | |||||
| int rmax = INT_MIN; | |||||
| int rmin = INT_MAX; | |||||
| while (numSamples > 0) | |||||
| { | |||||
| const int numToDo = (int) jmin (numSamples, (int64) bufferSize); | |||||
| read ((int**) tempBuffer, 2, startSampleInFile, numToDo, false); | |||||
| numSamples -= numToDo; | |||||
| for (int j = numChannels; --j >= 0;) | |||||
| { | |||||
| int bufMax = INT_MIN; | |||||
| int bufMin = INT_MAX; | |||||
| const int* const b = tempBuffer[j]; | |||||
| for (int i = 0; i < numToDo; ++i) | |||||
| { | |||||
| const int samp = b[i]; | |||||
| if (samp < bufMin) | |||||
| bufMin = samp; | |||||
| if (samp > bufMax) | |||||
| bufMax = samp; | |||||
| } | |||||
| if (j == 0) | |||||
| { | |||||
| lmax = jmax (lmax, bufMax); | |||||
| lmin = jmin (lmin, bufMin); | |||||
| } | |||||
| else | |||||
| { | |||||
| rmax = jmax (rmax, bufMax); | |||||
| rmin = jmin (rmin, bufMin); | |||||
| } | |||||
| } | |||||
| } | |||||
| if (numChannels <= 1) | |||||
| { | |||||
| rmax = lmax; | |||||
| rmin = lmin; | |||||
| } | |||||
| lowestLeft = lmin / (float)INT_MAX; | |||||
| highestLeft = lmax / (float)INT_MAX; | |||||
| lowestRight = rmin / (float)INT_MAX; | |||||
| highestRight = rmax / (float)INT_MAX; | |||||
| } | |||||
| } | |||||
| int64 AudioFormatReader::searchForLevel (int64 startSample, | |||||
| int64 numSamplesToSearch, | |||||
| const double magnitudeRangeMinimum, | |||||
| const double magnitudeRangeMaximum, | |||||
| const int minimumConsecutiveSamples) | |||||
| { | |||||
| if (numSamplesToSearch == 0) | |||||
| return -1; | |||||
| const int bufferSize = 4096; | |||||
| MemoryBlock tempSpace (bufferSize * sizeof (int) * 2 + 64); | |||||
| int* tempBuffer[3]; | |||||
| tempBuffer[0] = (int*) tempSpace.getData(); | |||||
| tempBuffer[1] = ((int*) tempSpace.getData()) + bufferSize; | |||||
| tempBuffer[2] = 0; | |||||
| int consecutive = 0; | |||||
| int64 firstMatchPos = -1; | |||||
| jassert (magnitudeRangeMaximum > magnitudeRangeMinimum); | |||||
| const double doubleMin = jlimit (0.0, (double) INT_MAX, magnitudeRangeMinimum * INT_MAX); | |||||
| const double doubleMax = jlimit (doubleMin, (double) INT_MAX, magnitudeRangeMaximum * INT_MAX); | |||||
| const int intMagnitudeRangeMinimum = roundDoubleToInt (doubleMin); | |||||
| const int intMagnitudeRangeMaximum = roundDoubleToInt (doubleMax); | |||||
| while (numSamplesToSearch != 0) | |||||
| { | |||||
| const int numThisTime = (int) jmin (abs64 (numSamplesToSearch), (int64) bufferSize); | |||||
| int64 bufferStart = startSample; | |||||
| if (numSamplesToSearch < 0) | |||||
| bufferStart -= numThisTime; | |||||
| if (bufferStart >= (int) lengthInSamples) | |||||
| break; | |||||
| read ((int**) tempBuffer, 2, bufferStart, numThisTime, false); | |||||
| int num = numThisTime; | |||||
| while (--num >= 0) | |||||
| { | |||||
| if (numSamplesToSearch < 0) | |||||
| --startSample; | |||||
| bool matches = false; | |||||
| const int index = (int) (startSample - bufferStart); | |||||
| if (usesFloatingPointData) | |||||
| { | |||||
| const float sample1 = fabsf (((float*) tempBuffer[0]) [index]); | |||||
| if (sample1 >= magnitudeRangeMinimum | |||||
| && sample1 <= magnitudeRangeMaximum) | |||||
| { | |||||
| matches = true; | |||||
| } | |||||
| else if (numChannels > 1) | |||||
| { | |||||
| const float sample2 = fabsf (((float*) tempBuffer[1]) [index]); | |||||
| matches = (sample2 >= magnitudeRangeMinimum | |||||
| && sample2 <= magnitudeRangeMaximum); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| const int sample1 = abs (tempBuffer[0] [index]); | |||||
| if (sample1 >= intMagnitudeRangeMinimum | |||||
| && sample1 <= intMagnitudeRangeMaximum) | |||||
| { | |||||
| matches = true; | |||||
| } | |||||
| else if (numChannels > 1) | |||||
| { | |||||
| const int sample2 = abs (tempBuffer[1][index]); | |||||
| matches = (sample2 >= intMagnitudeRangeMinimum | |||||
| && sample2 <= intMagnitudeRangeMaximum); | |||||
| } | |||||
| } | |||||
| if (matches) | |||||
| { | |||||
| if (firstMatchPos < 0) | |||||
| firstMatchPos = startSample; | |||||
| if (++consecutive >= minimumConsecutiveSamples) | |||||
| { | |||||
| if (firstMatchPos < 0 || firstMatchPos >= lengthInSamples) | |||||
| return -1; | |||||
| return firstMatchPos; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| consecutive = 0; | |||||
| firstMatchPos = -1; | |||||
| } | |||||
| if (numSamplesToSearch > 0) | |||||
| ++startSample; | |||||
| } | |||||
| if (numSamplesToSearch > 0) | |||||
| numSamplesToSearch -= numThisTime; | |||||
| else | |||||
| numSamplesToSearch += numThisTime; | |||||
| } | |||||
| return -1; | |||||
| } | |||||
| //============================================================================== | |||||
| AudioFormatWriter::AudioFormatWriter (OutputStream* const out, | |||||
| const String& formatName_, | |||||
| const double rate, | |||||
| const unsigned int numChannels_, | |||||
| const unsigned int bitsPerSample_) | |||||
| : sampleRate (rate), | |||||
| numChannels (numChannels_), | |||||
| bitsPerSample (bitsPerSample_), | |||||
| usesFloatingPointData (false), | |||||
| output (out), | |||||
| formatName (formatName_) | |||||
| { | |||||
| } | |||||
| AudioFormatWriter::~AudioFormatWriter() | |||||
| { | |||||
| delete output; | |||||
| } | |||||
| bool AudioFormatWriter::writeFromAudioReader (AudioFormatReader& reader, | |||||
| int64 startSample, | |||||
| int64 numSamplesToRead) | |||||
| { | |||||
| const int bufferSize = 16384; | |||||
| const int maxChans = 128; | |||||
| AudioSampleBuffer tempBuffer (reader.numChannels, bufferSize); | |||||
| int* buffers [maxChans]; | |||||
| for (int i = maxChans; --i >= 0;) | |||||
| buffers[i] = 0; | |||||
| if (numSamplesToRead < 0) | |||||
| numSamplesToRead = reader.lengthInSamples; | |||||
| while (numSamplesToRead > 0) | |||||
| { | |||||
| const int numToDo = (int) jmin (numSamplesToRead, (int64) bufferSize); | |||||
| for (int i = tempBuffer.getNumChannels(); --i >= 0;) | |||||
| buffers[i] = (int*) tempBuffer.getSampleData (i, 0); | |||||
| if (! reader.read (buffers, maxChans, startSample, numToDo, false)) | |||||
| return false; | |||||
| if (reader.usesFloatingPointData != isFloatingPoint()) | |||||
| { | |||||
| int** bufferChan = buffers; | |||||
| while (*bufferChan != 0) | |||||
| { | |||||
| int* b = *bufferChan++; | |||||
| if (isFloatingPoint()) | |||||
| { | |||||
| // int -> float | |||||
| const double factor = 1.0 / INT_MAX; | |||||
| for (int i = 0; i < numToDo; ++i) | |||||
| ((float*)b)[i] = (float) (factor * b[i]); | |||||
| } | |||||
| else | |||||
| { | |||||
| // float -> int | |||||
| for (int i = 0; i < numToDo; ++i) | |||||
| { | |||||
| const double samp = *(const float*) b; | |||||
| if (samp <= -1.0) | |||||
| *b++ = INT_MIN; | |||||
| else if (samp >= 1.0) | |||||
| *b++ = INT_MAX; | |||||
| else | |||||
| *b++ = roundDoubleToInt (INT_MAX * samp); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| if (! write ((const int**) buffers, numToDo)) | |||||
| return false; | |||||
| numSamplesToRead -= numToDo; | |||||
| startSample += numToDo; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| bool AudioFormatWriter::writeFromAudioSource (AudioSource& source, | |||||
| int numSamplesToRead, | |||||
| const int samplesPerBlock) | |||||
| { | |||||
| const int maxChans = 128; | |||||
| AudioSampleBuffer tempBuffer (getNumChannels(), samplesPerBlock); | |||||
| int* buffers [maxChans]; | |||||
| while (numSamplesToRead > 0) | |||||
| { | |||||
| const int numToDo = jmin (numSamplesToRead, samplesPerBlock); | |||||
| AudioSourceChannelInfo info; | |||||
| info.buffer = &tempBuffer; | |||||
| info.startSample = 0; | |||||
| info.numSamples = numToDo; | |||||
| info.clearActiveBufferRegion(); | |||||
| source.getNextAudioBlock (info); | |||||
| int i; | |||||
| for (i = maxChans; --i >= 0;) | |||||
| buffers[i] = 0; | |||||
| for (i = tempBuffer.getNumChannels(); --i >= 0;) | |||||
| buffers[i] = (int*) tempBuffer.getSampleData (i, 0); | |||||
| if (! isFloatingPoint()) | |||||
| { | |||||
| int** bufferChan = buffers; | |||||
| while (*bufferChan != 0) | |||||
| { | |||||
| int* b = *bufferChan++; | |||||
| // float -> int | |||||
| for (int j = numToDo; --j >= 0;) | |||||
| { | |||||
| const double samp = *(const float*) b; | |||||
| if (samp <= -1.0) | |||||
| *b++ = INT_MIN; | |||||
| else if (samp >= 1.0) | |||||
| *b++ = INT_MAX; | |||||
| else | |||||
| *b++ = roundDoubleToInt (INT_MAX * samp); | |||||
| } | |||||
| } | |||||
| } | |||||
| if (! write ((const int**) buffers, numToDo)) | |||||
| return false; | |||||
| numSamplesToRead -= numToDo; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| //============================================================================== | |||||
| AudioFormat::AudioFormat (const String& name, | |||||
| const tchar** const extensions) | |||||
| : formatName (name), | |||||
| fileExtensions (extensions) | |||||
| { | |||||
| } | |||||
| AudioFormat::~AudioFormat() | |||||
| { | |||||
| } | |||||
| //============================================================================== | |||||
| const String& AudioFormat::getFormatName() const | |||||
| { | |||||
| return formatName; | |||||
| } | |||||
| const StringArray& AudioFormat::getFileExtensions() const | |||||
| { | |||||
| return fileExtensions; | |||||
| } | |||||
| bool AudioFormat::canHandleFile (const File& f) | |||||
| { | |||||
| for (int i = 0; i < fileExtensions.size(); ++i) | |||||
| if (f.hasFileExtension (fileExtensions[i])) | |||||
| return true; | |||||
| return false; | |||||
| } | |||||
| bool AudioFormat::isCompressed() | |||||
| { | |||||
| return false; | |||||
| } | |||||
| const StringArray AudioFormat::getQualityOptions() | |||||
| { | |||||
| return StringArray(); | |||||
| } | |||||
| END_JUCE_NAMESPACE | |||||
| @@ -0,0 +1,172 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #ifndef __JUCE_AUDIOFORMAT_JUCEHEADER__ | |||||
| #define __JUCE_AUDIOFORMAT_JUCEHEADER__ | |||||
| #include "juce_AudioFormatReader.h" | |||||
| #include "juce_AudioFormatWriter.h" | |||||
| //============================================================================== | |||||
| /** | |||||
| Subclasses of AudioFormat are used to read and write different audio | |||||
| file formats. | |||||
| @see AudioFormatReader, AudioFormatWriter, WavAudioFormat, AiffAudioFormat | |||||
| */ | |||||
| class JUCE_API AudioFormat | |||||
| { | |||||
| public: | |||||
| //============================================================================== | |||||
| /** Destructor. */ | |||||
| virtual ~AudioFormat(); | |||||
| //============================================================================== | |||||
| /** Returns the name of this format. | |||||
| e.g. "WAV file" or "AIFF file" | |||||
| */ | |||||
| const String& getFormatName() const; | |||||
| /** Returns all the file extensions that might apply to a file of this format. | |||||
| The first item will be the one that's preferred when creating a new file. | |||||
| So for a wav file this might just return ".wav"; for an AIFF file it might | |||||
| return two items, ".aif" and ".aiff" | |||||
| */ | |||||
| const StringArray& getFileExtensions() const; | |||||
| //============================================================================== | |||||
| /** Returns true if this the given file can be read by this format. | |||||
| Subclasses shouldn't do too much work here, just check the extension or | |||||
| file type. The base class implementation just checks the file's extension | |||||
| against one of the ones that was registered in the constructor. | |||||
| */ | |||||
| virtual bool canHandleFile (const File& fileToTest); | |||||
| /** Returns a set of sample rates that the format can read and write. */ | |||||
| virtual const Array <int> getPossibleSampleRates() = 0; | |||||
| /** Returns a set of bit depths that the format can read and write. */ | |||||
| virtual const Array <int> getPossibleBitDepths() = 0; | |||||
| /** Returns true if the format can do 2-channel audio. */ | |||||
| virtual bool canDoStereo() = 0; | |||||
| /** Returns true if the format can do 1-channel audio. */ | |||||
| virtual bool canDoMono() = 0; | |||||
| /** Returns true if the format uses compressed data. */ | |||||
| virtual bool isCompressed(); | |||||
| /** Returns a list of different qualities that can be used when writing. | |||||
| Non-compressed formats will just return an empty array, but for something | |||||
| like Ogg-Vorbis or MP3, it might return a list of bit-rates, etc. | |||||
| When calling createWriterFor(), an index from this array is passed in to | |||||
| tell the format which option is required. | |||||
| */ | |||||
| virtual const StringArray getQualityOptions(); | |||||
| //============================================================================== | |||||
| /** Tries to create an object that can read from a stream containing audio | |||||
| data in this format. | |||||
| The reader object that is returned can be used to read from the stream, and | |||||
| should then be deleted by the caller. | |||||
| @param sourceStream the stream to read from - the AudioFormatReader object | |||||
| that is returned will delete this stream when it no longer | |||||
| needs it. | |||||
| @param deleteStreamIfOpeningFails if no reader can be created, this determines whether this method | |||||
| should delete the stream object that was passed-in. (If a valid | |||||
| reader is returned, it will always be in charge of deleting the | |||||
| stream, so this parameter is ignored) | |||||
| @see AudioFormatReader | |||||
| */ | |||||
| virtual AudioFormatReader* createReaderFor (InputStream* sourceStream, | |||||
| const bool deleteStreamIfOpeningFails) = 0; | |||||
| /** Tries to create an object that can write to a stream with this audio format. | |||||
| The writer object that is returned can be used to write to the stream, and | |||||
| should then be deleted by the caller. | |||||
| If the stream can't be created for some reason (e.g. the parameters passed in | |||||
| here aren't suitable), this will return 0. | |||||
| @param streamToWriteTo the stream that the data will go to - this will be | |||||
| deleted by the AudioFormatWriter object when it's no longer | |||||
| needed. If no AudioFormatWriter can be created by this method, | |||||
| the stream will NOT be deleted, so that the caller can re-use it | |||||
| to try to open a different format, etc | |||||
| @param sampleRateToUse the sample rate for the file, which must be one of the ones | |||||
| returned by getPossibleSampleRates() | |||||
| @param numberOfChannels the number of channels - this must be either 1 or 2, and | |||||
| the choice will depend on the results of canDoMono() and | |||||
| canDoStereo() | |||||
| @param bitsPerSample the bits per sample to use - this must be one of the values | |||||
| returned by getPossibleBitDepths() | |||||
| @param metadataValues a set of metadata values that the writer should try to write | |||||
| to the stream. Exactly what these are depends on the format, | |||||
| and the subclass doesn't actually have to do anything with | |||||
| them if it doesn't want to. Have a look at the specific format | |||||
| implementation classes to see possible values that can be | |||||
| used | |||||
| @param qualityOptionIndex the index of one of compression qualities returned by the | |||||
| getQualityOptions() method. If there aren't any quality options | |||||
| for this format, just pass 0 in this parameter, as it'll be | |||||
| ignored | |||||
| @see AudioFormatWriter | |||||
| */ | |||||
| virtual AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, | |||||
| double sampleRateToUse, | |||||
| unsigned int numberOfChannels, | |||||
| int bitsPerSample, | |||||
| const StringPairArray& metadataValues, | |||||
| int qualityOptionIndex) = 0; | |||||
| protected: | |||||
| /** Creates an AudioFormat object. | |||||
| @param formatName this sets the value that will be returned by getFormatName() | |||||
| @param fileExtensions a zero-terminated list of file extensions - this is what will | |||||
| be returned by getFileExtension() | |||||
| */ | |||||
| AudioFormat (const String& formatName, | |||||
| const tchar** const fileExtensions); | |||||
| private: | |||||
| //============================================================================== | |||||
| String formatName; | |||||
| StringArray fileExtensions; | |||||
| }; | |||||
| #endif // __JUCE_AUDIOFORMAT_JUCEHEADER__ | |||||
| @@ -0,0 +1,225 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #include "../../core/juce_StandardHeader.h" | |||||
| BEGIN_JUCE_NAMESPACE | |||||
| #include "juce_AudioFormatManager.h" | |||||
| #include "juce_AiffAudioFormat.h" | |||||
| #include "juce_WavAudioFormat.h" | |||||
| #include "juce_FlacAudioFormat.h" | |||||
| #include "juce_OggVorbisAudioFormat.h" | |||||
| #include "../../io/files/juce_FileInputStream.h" | |||||
| //============================================================================== | |||||
| AudioFormatManager::AudioFormatManager() | |||||
| : knownFormats (4), | |||||
| defaultFormatIndex (0) | |||||
| { | |||||
| } | |||||
| AudioFormatManager::~AudioFormatManager() | |||||
| { | |||||
| clearFormats(); | |||||
| clearSingletonInstance(); | |||||
| } | |||||
| juce_ImplementSingleton (AudioFormatManager); | |||||
| //============================================================================== | |||||
| void AudioFormatManager::registerFormat (AudioFormat* newFormat, | |||||
| const bool makeThisTheDefaultFormat) | |||||
| { | |||||
| jassert (newFormat != 0); | |||||
| if (newFormat != 0) | |||||
| { | |||||
| #ifdef JUCE_DEBUG | |||||
| for (int i = getNumKnownFormats(); --i >= 0;) | |||||
| { | |||||
| if (getKnownFormat (i)->getFormatName() == newFormat->getFormatName()) | |||||
| { | |||||
| jassertfalse // trying to add the same format twice! | |||||
| } | |||||
| } | |||||
| #endif | |||||
| if (makeThisTheDefaultFormat) | |||||
| defaultFormatIndex = knownFormats.size(); | |||||
| knownFormats.add (newFormat); | |||||
| } | |||||
| } | |||||
| void AudioFormatManager::registerBasicFormats() | |||||
| { | |||||
| #if JUCE_MAC | |||||
| registerFormat (new AiffAudioFormat(), true); | |||||
| registerFormat (new WavAudioFormat(), false); | |||||
| #else | |||||
| registerFormat (new WavAudioFormat(), true); | |||||
| registerFormat (new AiffAudioFormat(), false); | |||||
| #endif | |||||
| #if JUCE_USE_FLAC | |||||
| registerFormat (new FlacAudioFormat(), false); | |||||
| #endif | |||||
| #if JUCE_USE_OGGVORBIS | |||||
| registerFormat (new OggVorbisAudioFormat(), false); | |||||
| #endif | |||||
| } | |||||
| void AudioFormatManager::clearFormats() | |||||
| { | |||||
| for (int i = getNumKnownFormats(); --i >= 0;) | |||||
| { | |||||
| AudioFormat* const af = getKnownFormat(i); | |||||
| delete af; | |||||
| } | |||||
| knownFormats.clear(); | |||||
| defaultFormatIndex = 0; | |||||
| } | |||||
| int AudioFormatManager::getNumKnownFormats() const | |||||
| { | |||||
| return knownFormats.size(); | |||||
| } | |||||
| AudioFormat* AudioFormatManager::getKnownFormat (const int index) const | |||||
| { | |||||
| return (AudioFormat*) knownFormats [index]; | |||||
| } | |||||
| AudioFormat* AudioFormatManager::getDefaultFormat() const | |||||
| { | |||||
| return getKnownFormat (defaultFormatIndex); | |||||
| } | |||||
| AudioFormat* AudioFormatManager::findFormatForFileExtension (const String& fileExtension) const | |||||
| { | |||||
| String e (fileExtension); | |||||
| if (! e.startsWithChar (T('.'))) | |||||
| e = T(".") + e; | |||||
| for (int i = 0; i < getNumKnownFormats(); ++i) | |||||
| if (getKnownFormat(i)->getFileExtensions().contains (e, true)) | |||||
| return getKnownFormat(i); | |||||
| return 0; | |||||
| } | |||||
| const String AudioFormatManager::getWildcardForAllFormats() const | |||||
| { | |||||
| StringArray allExtensions; | |||||
| int i; | |||||
| for (i = 0; i < getNumKnownFormats(); ++i) | |||||
| allExtensions.addArray (getKnownFormat (i)->getFileExtensions()); | |||||
| allExtensions.trim(); | |||||
| allExtensions.removeEmptyStrings(); | |||||
| String s; | |||||
| for (i = 0; i < allExtensions.size(); ++i) | |||||
| { | |||||
| s << T('*'); | |||||
| if (! allExtensions[i].startsWithChar (T('.'))) | |||||
| s << T('.'); | |||||
| s << allExtensions[i]; | |||||
| if (i < allExtensions.size() - 1) | |||||
| s << T(';'); | |||||
| } | |||||
| return s; | |||||
| } | |||||
| //============================================================================== | |||||
| AudioFormatReader* AudioFormatManager::createReaderFor (const File& file) | |||||
| { | |||||
| // you need to actually register some formats before the manager can | |||||
| // use them to open a file! | |||||
| jassert (knownFormats.size() > 0); | |||||
| for (int i = 0; i < getNumKnownFormats(); ++i) | |||||
| { | |||||
| AudioFormat* const af = getKnownFormat(i); | |||||
| if (af->canHandleFile (file)) | |||||
| { | |||||
| InputStream* const in = file.createInputStream(); | |||||
| if (in != 0) | |||||
| { | |||||
| AudioFormatReader* const r = af->createReaderFor (in, true); | |||||
| if (r != 0) | |||||
| return r; | |||||
| } | |||||
| } | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| AudioFormatReader* AudioFormatManager::createReaderFor (InputStream* in) | |||||
| { | |||||
| // you need to actually register some formats before the manager can | |||||
| // use them to open a file! | |||||
| jassert (knownFormats.size() > 0); | |||||
| if (in != 0) | |||||
| { | |||||
| const int64 originalStreamPos = in->getPosition(); | |||||
| for (int i = 0; i < getNumKnownFormats(); ++i) | |||||
| { | |||||
| AudioFormatReader* const r = getKnownFormat(i)->createReaderFor (in, false); | |||||
| if (r != 0) | |||||
| return r; | |||||
| in->setPosition (originalStreamPos); | |||||
| // the stream that is passed-in must be capable of being repositioned so | |||||
| // that all the formats can have a go at opening it. | |||||
| jassert (in->getPosition() == originalStreamPos); | |||||
| } | |||||
| delete in; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| END_JUCE_NAMESPACE | |||||
| @@ -0,0 +1,144 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #ifndef __JUCE_AUDIOFORMATMANAGER_JUCEHEADER__ | |||||
| #define __JUCE_AUDIOFORMATMANAGER_JUCEHEADER__ | |||||
| #include "juce_AudioFormat.h" | |||||
| #include "../../core/juce_Singleton.h" | |||||
| //============================================================================== | |||||
| /** | |||||
| A class for keeping a list of available audio formats, and for deciding which | |||||
| one to use to open a given file. | |||||
| You can either use this class as a singleton object, or create instances of it | |||||
| yourself. Once created, use its registerFormat() method to tell it which | |||||
| formats it should use. | |||||
| @see AudioFormat | |||||
| */ | |||||
| class JUCE_API AudioFormatManager | |||||
| { | |||||
| public: | |||||
| //============================================================================== | |||||
| /** Creates an empty format manager. | |||||
| Before it'll be any use, you'll need to call registerFormat() with all the | |||||
| formats you want it to be able to recognise. | |||||
| */ | |||||
| AudioFormatManager(); | |||||
| /** Destructor. */ | |||||
| ~AudioFormatManager(); | |||||
| juce_DeclareSingleton (AudioFormatManager, false); | |||||
| //============================================================================== | |||||
| /** Adds a format to the manager's list of available file types. | |||||
| The object passed-in will be deleted by this object, so don't keep a pointer | |||||
| to it! | |||||
| If makeThisTheDefaultFormat is true, then the getDefaultFormat() method will | |||||
| return this one when called. | |||||
| */ | |||||
| void registerFormat (AudioFormat* newFormat, | |||||
| const bool makeThisTheDefaultFormat); | |||||
| /** Handy method to make it easy to register the formats that come with Juce. | |||||
| Currently, this will add WAV and AIFF to the list. | |||||
| */ | |||||
| void registerBasicFormats(); | |||||
| /** Clears the list of known formats. */ | |||||
| void clearFormats(); | |||||
| /** Returns the number of currently registered file formats. */ | |||||
| int getNumKnownFormats() const; | |||||
| /** Returns one of the registered file formats. */ | |||||
| AudioFormat* getKnownFormat (const int index) const; | |||||
| /** Looks for which of the known formats is listed as being for a given file | |||||
| extension. | |||||
| The extension may have a dot before it, so e.g. ".wav" or "wav" are both ok. | |||||
| */ | |||||
| AudioFormat* findFormatForFileExtension (const String& fileExtension) const; | |||||
| /** Returns the format which has been set as the default one. | |||||
| You can set a format as being the default when it is registered. It's useful | |||||
| when you want to write to a file, because the best format may change between | |||||
| platforms, e.g. AIFF is preferred on the Mac, WAV on Windows. | |||||
| If none has been set as the default, this method will just return the first | |||||
| one in the list. | |||||
| */ | |||||
| AudioFormat* getDefaultFormat() const; | |||||
| /** Returns a set of wildcards for file-matching that contains the extensions for | |||||
| all known formats. | |||||
| E.g. if might return "*.wav;*.aiff" if it just knows about wavs and aiffs. | |||||
| */ | |||||
| const String getWildcardForAllFormats() const; | |||||
| //============================================================================== | |||||
| /** Searches through the known formats to try to create a suitable reader for | |||||
| this file. | |||||
| If none of the registered formats can open the file, it'll return 0. If it | |||||
| returns a reader, it's the caller's responsibility to delete the reader. | |||||
| */ | |||||
| AudioFormatReader* createReaderFor (const File& audioFile); | |||||
| /** Searches through the known formats to try to create a suitable reader for | |||||
| this stream. | |||||
| The stream object that is passed-in will be deleted by this method or by the | |||||
| reader that is returned, so the caller should not keep any references to it. | |||||
| The stream that is passed-in must be capable of being repositioned so | |||||
| that all the formats can have a go at opening it. | |||||
| If none of the registered formats can open the stream, it'll return 0. If it | |||||
| returns a reader, it's the caller's responsibility to delete the reader. | |||||
| */ | |||||
| AudioFormatReader* createReaderFor (InputStream* audioFileStream); | |||||
| //============================================================================== | |||||
| juce_UseDebuggingNewOperator | |||||
| private: | |||||
| VoidArray knownFormats; | |||||
| int defaultFormatIndex; | |||||
| }; | |||||
| #endif // __JUCE_AUDIOFORMATMANAGER_JUCEHEADER__ | |||||
| @@ -0,0 +1,229 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #ifndef __JUCE_AUDIOFORMATREADER_JUCEHEADER__ | |||||
| #define __JUCE_AUDIOFORMATREADER_JUCEHEADER__ | |||||
| #include "../../io/streams/juce_InputStream.h" | |||||
| #include "../../text/juce_StringPairArray.h" | |||||
| class AudioFormat; | |||||
| //============================================================================== | |||||
| /** | |||||
| Reads samples from an audio file stream. | |||||
| A subclass that reads a specific type of audio format will be created by | |||||
| an AudioFormat object. | |||||
| @see AudioFormat, AudioFormatWriter | |||||
| */ | |||||
| class JUCE_API AudioFormatReader | |||||
| { | |||||
| protected: | |||||
| //============================================================================== | |||||
| /** Creates an AudioFormatReader object. | |||||
| @param sourceStream the stream to read from - this will be deleted | |||||
| by this object when it is no longer needed. (Some | |||||
| specialised readers might not use this parameter and | |||||
| can leave it as 0). | |||||
| @param formatName the description that will be returned by the getFormatName() | |||||
| method | |||||
| */ | |||||
| AudioFormatReader (InputStream* const sourceStream, | |||||
| const String& formatName); | |||||
| public: | |||||
| /** Destructor. */ | |||||
| virtual ~AudioFormatReader(); | |||||
| //============================================================================== | |||||
| /** Returns a description of what type of format this is. | |||||
| E.g. "AIFF" | |||||
| */ | |||||
| const String getFormatName() const throw() { return formatName; } | |||||
| //============================================================================== | |||||
| /** Reads samples from the stream. | |||||
| @param destSamples an array of buffers into which the sample data for each | |||||
| channel will be written. | |||||
| If the format is fixed-point, each channel will be written | |||||
| as an array of 32-bit signed integers using the full | |||||
| range -0x80000000 to 0x7fffffff, regardless of the source's | |||||
| bit-depth. If it is a floating-point format, you should cast | |||||
| the resulting array to a (float**) to get the values (in the | |||||
| range -1.0 to 1.0 or beyond) | |||||
| If the format is stereo, then destSamples[0] is the left channel | |||||
| data, and destSamples[1] is the right channel. | |||||
| The numDestChannels parameter indicates how many pointers this array | |||||
| contains, but some of these pointers can be null if you don't want to | |||||
| read data for some of the channels | |||||
| @param numDestChannels the number of array elements in the destChannels array | |||||
| @param startSampleInSource the position in the audio file or stream at which the samples | |||||
| should be read, as a number of samples from the start of the | |||||
| stream. It's ok for this to be beyond the start or end of the | |||||
| available data - any samples that are out-of-range will be returned | |||||
| as zeros. | |||||
| @param numSamplesToRead the number of samples to read. If this is greater than the number | |||||
| of samples that the file or stream contains. the result will be padded | |||||
| with zeros | |||||
| @param fillLeftoverChannelsWithCopies if true, this indicates that if there's no source data available | |||||
| for some of the channels that you pass in, then they should be filled with | |||||
| copies of valid source channels. | |||||
| E.g. if you're reading a mono file and you pass 2 channels to this method, then | |||||
| if fillLeftoverChannelsWithCopies is true, both destination channels will be filled | |||||
| with the same data from the file's single channel. If fillLeftoverChannelsWithCopies | |||||
| was false, then only the first channel would be filled with the file's contents, and | |||||
| the second would be cleared. If there are many channels, e.g. you try to read 4 channels | |||||
| from a stereo file, then the last 3 would all end up with copies of the same data. | |||||
| @returns true if the operation succeeded, false if there was an error. Note | |||||
| that reading sections of data beyond the extent of the stream isn't an | |||||
| error - the reader should just return zeros for these regions | |||||
| @see readMaxLevels | |||||
| */ | |||||
| bool read (int** destSamples, | |||||
| int numDestChannels, | |||||
| int64 startSampleInSource, | |||||
| int numSamplesToRead, | |||||
| const bool fillLeftoverChannelsWithCopies); | |||||
| /** Finds the highest and lowest sample levels from a section of the audio stream. | |||||
| This will read a block of samples from the stream, and measure the | |||||
| highest and lowest sample levels from the channels in that section, returning | |||||
| these as normalised floating-point levels. | |||||
| @param startSample the offset into the audio stream to start reading from. It's | |||||
| ok for this to be beyond the start or end of the stream. | |||||
| @param numSamples how many samples to read | |||||
| @param lowestLeft on return, this is the lowest absolute sample from the left channel | |||||
| @param highestLeft on return, this is the highest absolute sample from the left channel | |||||
| @param lowestRight on return, this is the lowest absolute sample from the right | |||||
| channel (if there is one) | |||||
| @param highestRight on return, this is the highest absolute sample from the right | |||||
| channel (if there is one) | |||||
| @see read | |||||
| */ | |||||
| virtual void readMaxLevels (int64 startSample, | |||||
| int64 numSamples, | |||||
| float& lowestLeft, | |||||
| float& highestLeft, | |||||
| float& lowestRight, | |||||
| float& highestRight); | |||||
| /** Scans the source looking for a sample whose magnitude is in a specified range. | |||||
| This will read from the source, either forwards or backwards between two sample | |||||
| positions, until it finds a sample whose magnitude lies between two specified levels. | |||||
| If it finds a suitable sample, it returns its position; if not, it will return -1. | |||||
| There's also a minimumConsecutiveSamples setting to help avoid spikes or zero-crossing | |||||
| points when you're searching for a continuous range of samples | |||||
| @param startSample the first sample to look at | |||||
| @param numSamplesToSearch the number of samples to scan. If this value is negative, | |||||
| the search will go backwards | |||||
| @param magnitudeRangeMinimum the lowest magnitude (inclusive) that is considered a hit, from 0 to 1.0 | |||||
| @param magnitudeRangeMaximum the highest magnitude (inclusive) that is considered a hit, from 0 to 1.0 | |||||
| @param minimumConsecutiveSamples if this is > 0, the method will only look for a sequence | |||||
| of this many consecutive samples, all of which lie | |||||
| within the target range. When it finds such a sequence, | |||||
| it returns the position of the first in-range sample | |||||
| it found (i.e. the earliest one if scanning forwards, the | |||||
| latest one if scanning backwards) | |||||
| */ | |||||
| int64 searchForLevel (int64 startSample, | |||||
| int64 numSamplesToSearch, | |||||
| const double magnitudeRangeMinimum, | |||||
| const double magnitudeRangeMaximum, | |||||
| const int minimumConsecutiveSamples); | |||||
| //============================================================================== | |||||
| /** The sample-rate of the stream. */ | |||||
| double sampleRate; | |||||
| /** The number of bits per sample, e.g. 16, 24, 32. */ | |||||
| unsigned int bitsPerSample; | |||||
| /** The total number of samples in the audio stream. */ | |||||
| int64 lengthInSamples; | |||||
| /** The total number of channels in the audio stream. */ | |||||
| unsigned int numChannels; | |||||
| /** Indicates whether the data is floating-point or fixed. */ | |||||
| bool usesFloatingPointData; | |||||
| /** A set of metadata values that the reader has pulled out of the stream. | |||||
| Exactly what these values are depends on the format, so you can | |||||
| check out the format implementation code to see what kind of stuff | |||||
| they understand. | |||||
| */ | |||||
| StringPairArray metadataValues; | |||||
| /** The input stream, for use by subclasses. */ | |||||
| InputStream* input; | |||||
| //============================================================================== | |||||
| /** Subclasses must implement this method to perform the low-level read operation. | |||||
| Callers should use read() instead of calling this directly. | |||||
| @param destSamples the array of destination buffers to fill. Some of these | |||||
| pointers may be null | |||||
| @param numDestChannels the number of items in the destSamples array. This | |||||
| value is guaranteed not to be greater than the number of | |||||
| channels that this reader object contains | |||||
| @param startOffsetInDestBuffer the number of samples from the start of the | |||||
| dest data at which to begin writing | |||||
| @param startSampleInFile the number of samples into the source data at which | |||||
| to begin reading. This value is guaranteed to be >= 0. | |||||
| @param numSamples the number of samples to read | |||||
| */ | |||||
| virtual bool readSamples (int** destSamples, | |||||
| int numDestChannels, | |||||
| int startOffsetInDestBuffer, | |||||
| int64 startSampleInFile, | |||||
| int numSamples) = 0; | |||||
| //============================================================================== | |||||
| juce_UseDebuggingNewOperator | |||||
| private: | |||||
| String formatName; | |||||
| AudioFormatReader (const AudioFormatReader&); | |||||
| const AudioFormatReader& operator= (const AudioFormatReader&); | |||||
| }; | |||||
| #endif // __JUCE_AUDIOFORMATREADER_JUCEHEADER__ | |||||
| @@ -0,0 +1,168 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #ifndef __JUCE_AUDIOFORMATWRITER_JUCEHEADER__ | |||||
| #define __JUCE_AUDIOFORMATWRITER_JUCEHEADER__ | |||||
| #include "../../io/files/juce_FileOutputStream.h" | |||||
| #include "juce_AudioFormatReader.h" | |||||
| #include "../audio_sources/juce_AudioSource.h" | |||||
| //============================================================================== | |||||
| /** | |||||
| Writes samples to an audio file stream. | |||||
| A subclass that writes a specific type of audio format will be created by | |||||
| an AudioFormat object. | |||||
| After creating one of these with the AudioFormat::createWriterFor() method | |||||
| you can call its write() method to store the samples, and then delete it. | |||||
| @see AudioFormat, AudioFormatReader | |||||
| */ | |||||
| class JUCE_API AudioFormatWriter | |||||
| { | |||||
| protected: | |||||
| //============================================================================== | |||||
| /** Creates an AudioFormatWriter object. | |||||
| @param destStream the stream to write to - this will be deleted | |||||
| by this object when it is no longer needed | |||||
| @param formatName the description that will be returned by the getFormatName() | |||||
| method | |||||
| @param sampleRate the sample rate to use - the base class just stores | |||||
| this value, it doesn't do anything with it | |||||
| @param numberOfChannels the number of channels to write - the base class just stores | |||||
| this value, it doesn't do anything with it | |||||
| @param bitsPerSample the bit depth of the stream - the base class just stores | |||||
| this value, it doesn't do anything with it | |||||
| */ | |||||
| AudioFormatWriter (OutputStream* const destStream, | |||||
| const String& formatName, | |||||
| const double sampleRate, | |||||
| const unsigned int numberOfChannels, | |||||
| const unsigned int bitsPerSample); | |||||
| public: | |||||
| /** Destructor. */ | |||||
| virtual ~AudioFormatWriter(); | |||||
| //============================================================================== | |||||
| /** Returns a description of what type of format this is. | |||||
| E.g. "AIFF file" | |||||
| */ | |||||
| const String getFormatName() const throw() { return formatName; } | |||||
| //============================================================================== | |||||
| /** Writes a set of samples to the audio stream. | |||||
| Note that if you're trying to write the contents of an AudioSampleBuffer, you | |||||
| can use AudioSampleBuffer::writeToAudioWriter(). | |||||
| @param samplesToWrite an array of arrays containing the sample data for | |||||
| each channel to write. This is a zero-terminated | |||||
| array of arrays, and can contain a different number | |||||
| of channels than the actual stream uses, and the | |||||
| writer should do its best to cope with this. | |||||
| If the format is fixed-point, each channel will be formatted | |||||
| as an array of signed integers using the full 32-bit | |||||
| range -0x80000000 to 0x7fffffff, regardless of the source's | |||||
| bit-depth. If it is a floating-point format, you should treat | |||||
| the arrays as arrays of floats, and just cast it to an (int**) | |||||
| to pass it into the method. | |||||
| @param numSamples the number of samples to write | |||||
| */ | |||||
| virtual bool write (const int** samplesToWrite, | |||||
| int numSamples) = 0; | |||||
| //============================================================================== | |||||
| /** Reads a section of samples from an AudioFormatReader, and writes these to | |||||
| the output. | |||||
| This will take care of any floating-point conversion that's required to convert | |||||
| between the two formats. It won't deal with sample-rate conversion, though. | |||||
| If numSamplesToRead < 0, it will write the entire length of the reader. | |||||
| @returns false if it can't read or write properly during the operation | |||||
| */ | |||||
| bool writeFromAudioReader (AudioFormatReader& reader, | |||||
| int64 startSample, | |||||
| int64 numSamplesToRead); | |||||
| /** Reads some samples from an AudioSource, and writes these to the output. | |||||
| The source must already have been initialised with the AudioSource::prepareToPlay() method | |||||
| @param source the source to read from | |||||
| @param numSamplesToRead total number of samples to read and write | |||||
| @param samplesPerBlock the maximum number of samples to fetch from the source | |||||
| @returns false if it can't read or write properly during the operation | |||||
| */ | |||||
| bool writeFromAudioSource (AudioSource& source, | |||||
| int numSamplesToRead, | |||||
| const int samplesPerBlock = 2048); | |||||
| //============================================================================== | |||||
| /** Returns the sample rate being used. */ | |||||
| double getSampleRate() const throw() { return sampleRate; } | |||||
| /** Returns the number of channels being written. */ | |||||
| int getNumChannels() const throw() { return numChannels; } | |||||
| /** Returns the bit-depth of the data being written. */ | |||||
| int getBitsPerSample() const throw() { return bitsPerSample; } | |||||
| /** Returns true if it's a floating-point format, false if it's fixed-point. */ | |||||
| bool isFloatingPoint() const throw() { return usesFloatingPointData; } | |||||
| //============================================================================== | |||||
| juce_UseDebuggingNewOperator | |||||
| protected: | |||||
| /** The sample rate of the stream. */ | |||||
| double sampleRate; | |||||
| /** The number of channels being written to the stream. */ | |||||
| unsigned int numChannels; | |||||
| /** The bit depth of the file. */ | |||||
| unsigned int bitsPerSample; | |||||
| /** True if it's a floating-point format, false if it's fixed-point. */ | |||||
| bool usesFloatingPointData; | |||||
| /** The output stream for Use by subclasses. */ | |||||
| OutputStream* output; | |||||
| private: | |||||
| String formatName; | |||||
| }; | |||||
| #endif // __JUCE_AUDIOFORMATWRITER_JUCEHEADER__ | |||||
| @@ -0,0 +1,96 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #include "../../core/juce_StandardHeader.h" | |||||
| BEGIN_JUCE_NAMESPACE | |||||
| #include "juce_AudioSubsectionReader.h" | |||||
| //============================================================================== | |||||
| AudioSubsectionReader::AudioSubsectionReader (AudioFormatReader* const source_, | |||||
| const int64 startSample_, | |||||
| const int64 length_, | |||||
| const bool deleteSourceWhenDeleted_) | |||||
| : AudioFormatReader (0, source_->getFormatName()), | |||||
| source (source_), | |||||
| startSample (startSample_), | |||||
| deleteSourceWhenDeleted (deleteSourceWhenDeleted_) | |||||
| { | |||||
| length = jmin (jmax ((int64) 0, source->lengthInSamples - startSample), length_); | |||||
| sampleRate = source->sampleRate; | |||||
| bitsPerSample = source->bitsPerSample; | |||||
| lengthInSamples = length; | |||||
| numChannels = source->numChannels; | |||||
| usesFloatingPointData = source->usesFloatingPointData; | |||||
| } | |||||
| AudioSubsectionReader::~AudioSubsectionReader() | |||||
| { | |||||
| if (deleteSourceWhenDeleted) | |||||
| delete source; | |||||
| } | |||||
| //============================================================================== | |||||
| bool AudioSubsectionReader::readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, | |||||
| int64 startSampleInFile, int numSamples) | |||||
| { | |||||
| if (startSampleInFile + numSamples > length) | |||||
| { | |||||
| for (int i = numDestChannels; --i >= 0;) | |||||
| if (destSamples[i] != 0) | |||||
| zeromem (destSamples[i], sizeof (int) * numSamples); | |||||
| numSamples = jmin (numSamples, (int) (length - startSampleInFile)); | |||||
| if (numSamples <= 0) | |||||
| return true; | |||||
| } | |||||
| return source->readSamples (destSamples, numDestChannels, startOffsetInDestBuffer, | |||||
| startSampleInFile + startSample, numSamples); | |||||
| } | |||||
| void AudioSubsectionReader::readMaxLevels (int64 startSampleInFile, | |||||
| int64 numSamples, | |||||
| float& lowestLeft, | |||||
| float& highestLeft, | |||||
| float& lowestRight, | |||||
| float& highestRight) | |||||
| { | |||||
| startSampleInFile = jmax ((int64) 0, startSampleInFile); | |||||
| numSamples = jmax ((int64) 0, jmin (numSamples, length - startSampleInFile)); | |||||
| source->readMaxLevels (startSampleInFile + startSample, | |||||
| numSamples, | |||||
| lowestLeft, | |||||
| highestLeft, | |||||
| lowestRight, | |||||
| highestRight); | |||||
| } | |||||
| END_JUCE_NAMESPACE | |||||
| @@ -0,0 +1,93 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #ifndef __JUCE_AUDIOSUBSECTIONREADER_JUCEHEADER__ | |||||
| #define __JUCE_AUDIOSUBSECTIONREADER_JUCEHEADER__ | |||||
| #include "juce_AudioFormatReader.h" | |||||
| //============================================================================== | |||||
| /** | |||||
| This class is used to wrap an AudioFormatReader and only read from a | |||||
| subsection of the file. | |||||
| So if you have a reader which can read a 1000 sample file, you could wrap it | |||||
| in one of these to only access, e.g. samples 100 to 200, and any samples | |||||
| outside that will come back as 0. Accessing sample 0 from this reader will | |||||
| actually read the first sample from the other's subsection, which might | |||||
| be at a non-zero position. | |||||
| @see AudioFormatReader | |||||
| */ | |||||
| class JUCE_API AudioSubsectionReader : public AudioFormatReader | |||||
| { | |||||
| public: | |||||
| //============================================================================== | |||||
| /** Creates a AudioSubsectionReader for a given data source. | |||||
| @param sourceReader the source reader from which we'll be taking data | |||||
| @param subsectionStartSample the sample within the source reader which will be | |||||
| mapped onto sample 0 for this reader. | |||||
| @param subsectionLength the number of samples from the source that will | |||||
| make up the subsection. If this reader is asked for | |||||
| any samples beyond this region, it will return zero. | |||||
| @param deleteSourceWhenDeleted if true, the sourceReader object will be deleted when | |||||
| this object is deleted. | |||||
| */ | |||||
| AudioSubsectionReader (AudioFormatReader* const sourceReader, | |||||
| const int64 subsectionStartSample, | |||||
| const int64 subsectionLength, | |||||
| const bool deleteSourceWhenDeleted); | |||||
| /** Destructor. */ | |||||
| ~AudioSubsectionReader(); | |||||
| //============================================================================== | |||||
| bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, | |||||
| int64 startSampleInFile, int numSamples); | |||||
| void readMaxLevels (int64 startSample, | |||||
| int64 numSamples, | |||||
| float& lowestLeft, | |||||
| float& highestLeft, | |||||
| float& lowestRight, | |||||
| float& highestRight); | |||||
| //============================================================================== | |||||
| juce_UseDebuggingNewOperator | |||||
| private: | |||||
| AudioFormatReader* const source; | |||||
| int64 startSample, length; | |||||
| const bool deleteSourceWhenDeleted; | |||||
| AudioSubsectionReader (const AudioSubsectionReader&); | |||||
| const AudioSubsectionReader& operator= (const AudioSubsectionReader&); | |||||
| }; | |||||
| #endif // __JUCE_AUDIOSUBSECTIONREADER_JUCEHEADER__ | |||||
| @@ -0,0 +1,535 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #include "../../core/juce_StandardHeader.h" | |||||
| BEGIN_JUCE_NAMESPACE | |||||
| #include "juce_AudioThumbnail.h" | |||||
| #include "juce_AudioThumbnailCache.h" | |||||
| const int timeBeforeDeletingReader = 2000; | |||||
| //============================================================================== | |||||
| struct AudioThumbnailDataFormat | |||||
| { | |||||
| char thumbnailMagic[4]; | |||||
| int samplesPerThumbSample; | |||||
| int64 totalSamples; // source samples | |||||
| int64 numFinishedSamples; // source samples | |||||
| int numThumbnailSamples; | |||||
| int numChannels; | |||||
| int sampleRate; | |||||
| char future[16]; | |||||
| char data[1]; | |||||
| }; | |||||
| #if JUCE_BIG_ENDIAN | |||||
| static void swap (int& n) { n = (int) swapByteOrder ((uint32) n); } | |||||
| static void swap (int64& n) { n = (int64) swapByteOrder ((uint64) n); } | |||||
| #endif | |||||
| static void swapEndiannessIfNeeded (AudioThumbnailDataFormat* const d) | |||||
| { | |||||
| (void) d; | |||||
| #if JUCE_BIG_ENDIAN | |||||
| swap (d->samplesPerThumbSample); | |||||
| swap (d->totalSamples); | |||||
| swap (d->numFinishedSamples); | |||||
| swap (d->numThumbnailSamples); | |||||
| swap (d->numChannels); | |||||
| swap (d->sampleRate); | |||||
| #endif | |||||
| } | |||||
| //============================================================================== | |||||
| AudioThumbnail::AudioThumbnail (const int orginalSamplesPerThumbnailSample_, | |||||
| AudioFormatManager& formatManagerToUse_, | |||||
| AudioThumbnailCache& cacheToUse) | |||||
| : formatManagerToUse (formatManagerToUse_), | |||||
| cache (cacheToUse), | |||||
| source (0), | |||||
| reader (0), | |||||
| orginalSamplesPerThumbnailSample (orginalSamplesPerThumbnailSample_) | |||||
| { | |||||
| clear(); | |||||
| } | |||||
| AudioThumbnail::~AudioThumbnail() | |||||
| { | |||||
| cache.removeThumbnail (this); | |||||
| const ScopedLock sl (readerLock); | |||||
| deleteAndZero (reader); | |||||
| delete source; | |||||
| } | |||||
| void AudioThumbnail::setSource (InputSource* const newSource) | |||||
| { | |||||
| cache.removeThumbnail (this); | |||||
| timerCallback(); // stops the timer and deletes the reader | |||||
| delete source; | |||||
| source = newSource; | |||||
| clear(); | |||||
| if (newSource != 0 | |||||
| && ! (cache.loadThumb (*this, newSource->hashCode()) | |||||
| && isFullyLoaded())) | |||||
| { | |||||
| { | |||||
| const ScopedLock sl (readerLock); | |||||
| reader = createReader(); | |||||
| } | |||||
| if (reader != 0) | |||||
| { | |||||
| initialiseFromAudioFile (*reader); | |||||
| cache.addThumbnail (this); | |||||
| } | |||||
| } | |||||
| sendChangeMessage (this); | |||||
| } | |||||
| bool AudioThumbnail::useTimeSlice() | |||||
| { | |||||
| const ScopedLock sl (readerLock); | |||||
| if (isFullyLoaded()) | |||||
| { | |||||
| if (reader != 0) | |||||
| startTimer (timeBeforeDeletingReader); | |||||
| cache.removeThumbnail (this); | |||||
| return false; | |||||
| } | |||||
| if (reader == 0) | |||||
| reader = createReader(); | |||||
| if (reader != 0) | |||||
| { | |||||
| readNextBlockFromAudioFile (*reader); | |||||
| stopTimer(); | |||||
| sendChangeMessage (this); | |||||
| const bool justFinished = isFullyLoaded(); | |||||
| if (justFinished) | |||||
| cache.storeThumb (*this, source->hashCode()); | |||||
| return ! justFinished; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| AudioFormatReader* AudioThumbnail::createReader() const | |||||
| { | |||||
| if (source != 0) | |||||
| { | |||||
| InputStream* const audioFileStream = source->createInputStream(); | |||||
| if (audioFileStream != 0) | |||||
| return formatManagerToUse.createReaderFor (audioFileStream); | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| void AudioThumbnail::timerCallback() | |||||
| { | |||||
| stopTimer(); | |||||
| const ScopedLock sl (readerLock); | |||||
| deleteAndZero (reader); | |||||
| } | |||||
| void AudioThumbnail::clear() | |||||
| { | |||||
| data.setSize (sizeof (AudioThumbnailDataFormat) + 3); | |||||
| AudioThumbnailDataFormat* const d = (AudioThumbnailDataFormat*) data.getData(); | |||||
| d->thumbnailMagic[0] = 'j'; | |||||
| d->thumbnailMagic[1] = 'a'; | |||||
| d->thumbnailMagic[2] = 't'; | |||||
| d->thumbnailMagic[3] = 'm'; | |||||
| d->samplesPerThumbSample = orginalSamplesPerThumbnailSample; | |||||
| d->totalSamples = 0; | |||||
| d->numFinishedSamples = 0; | |||||
| d->numThumbnailSamples = 0; | |||||
| d->numChannels = 0; | |||||
| d->sampleRate = 0; | |||||
| numSamplesCached = 0; | |||||
| cacheNeedsRefilling = true; | |||||
| } | |||||
| void AudioThumbnail::loadFrom (InputStream& input) | |||||
| { | |||||
| data.setSize (0); | |||||
| input.readIntoMemoryBlock (data); | |||||
| AudioThumbnailDataFormat* const d = (AudioThumbnailDataFormat*) data.getData(); | |||||
| swapEndiannessIfNeeded (d); | |||||
| if (! (d->thumbnailMagic[0] == 'j' | |||||
| && d->thumbnailMagic[1] == 'a' | |||||
| && d->thumbnailMagic[2] == 't' | |||||
| && d->thumbnailMagic[3] == 'm')) | |||||
| { | |||||
| clear(); | |||||
| } | |||||
| numSamplesCached = 0; | |||||
| cacheNeedsRefilling = true; | |||||
| } | |||||
| void AudioThumbnail::saveTo (OutputStream& output) const | |||||
| { | |||||
| AudioThumbnailDataFormat* const d = (AudioThumbnailDataFormat*) data.getData(); | |||||
| swapEndiannessIfNeeded (d); | |||||
| output.write (data.getData(), data.getSize()); | |||||
| swapEndiannessIfNeeded (d); | |||||
| } | |||||
| bool AudioThumbnail::initialiseFromAudioFile (AudioFormatReader& reader) | |||||
| { | |||||
| AudioThumbnailDataFormat* d = (AudioThumbnailDataFormat*) data.getData(); | |||||
| d->totalSamples = reader.lengthInSamples; | |||||
| d->numChannels = jmin (2, reader.numChannels); | |||||
| d->numFinishedSamples = 0; | |||||
| d->sampleRate = roundDoubleToInt (reader.sampleRate); | |||||
| d->numThumbnailSamples = (int) (d->totalSamples / d->samplesPerThumbSample) + 1; | |||||
| data.setSize (sizeof (AudioThumbnailDataFormat) + 3 + d->numThumbnailSamples * d->numChannels * 2); | |||||
| d = (AudioThumbnailDataFormat*) data.getData(); | |||||
| zeromem (&(d->data[0]), d->numThumbnailSamples * d->numChannels * 2); | |||||
| return d->totalSamples > 0; | |||||
| } | |||||
| bool AudioThumbnail::readNextBlockFromAudioFile (AudioFormatReader& reader) | |||||
| { | |||||
| AudioThumbnailDataFormat* const d = (AudioThumbnailDataFormat*) data.getData(); | |||||
| if (d->numFinishedSamples < d->totalSamples) | |||||
| { | |||||
| const int numToDo = (int) jmin ((int64) 65536, d->totalSamples - d->numFinishedSamples); | |||||
| generateSection (reader, | |||||
| d->numFinishedSamples, | |||||
| numToDo); | |||||
| d->numFinishedSamples += numToDo; | |||||
| } | |||||
| cacheNeedsRefilling = true; | |||||
| return (d->numFinishedSamples < d->totalSamples); | |||||
| } | |||||
| int AudioThumbnail::getNumChannels() const throw() | |||||
| { | |||||
| const AudioThumbnailDataFormat* const d = (const AudioThumbnailDataFormat*) data.getData(); | |||||
| jassert (d != 0); | |||||
| return d->numChannels; | |||||
| } | |||||
| double AudioThumbnail::getTotalLength() const throw() | |||||
| { | |||||
| const AudioThumbnailDataFormat* const d = (const AudioThumbnailDataFormat*) data.getData(); | |||||
| jassert (d != 0); | |||||
| if (d->sampleRate > 0) | |||||
| return d->totalSamples / (double)d->sampleRate; | |||||
| else | |||||
| return 0.0; | |||||
| } | |||||
| void AudioThumbnail::generateSection (AudioFormatReader& reader, | |||||
| int64 startSample, | |||||
| int numSamples) | |||||
| { | |||||
| AudioThumbnailDataFormat* const d = (AudioThumbnailDataFormat*) data.getData(); | |||||
| jassert (d != 0); | |||||
| int firstDataPos = (int) (startSample / d->samplesPerThumbSample); | |||||
| int lastDataPos = (int) ((startSample + numSamples) / d->samplesPerThumbSample); | |||||
| char* l = getChannelData (0); | |||||
| char* r = getChannelData (1); | |||||
| for (int i = firstDataPos; i < lastDataPos; ++i) | |||||
| { | |||||
| const int sourceStart = i * d->samplesPerThumbSample; | |||||
| const int sourceEnd = sourceStart + d->samplesPerThumbSample; | |||||
| float lowestLeft, highestLeft, lowestRight, highestRight; | |||||
| reader.readMaxLevels (sourceStart, | |||||
| sourceEnd - sourceStart, | |||||
| lowestLeft, | |||||
| highestLeft, | |||||
| lowestRight, | |||||
| highestRight); | |||||
| int n = i * 2; | |||||
| if (r != 0) | |||||
| { | |||||
| l [n] = (char) jlimit (-128.0f, 127.0f, lowestLeft * 127.0f); | |||||
| r [n++] = (char) jlimit (-128.0f, 127.0f, lowestRight * 127.0f); | |||||
| l [n] = (char) jlimit (-128.0f, 127.0f, highestLeft * 127.0f); | |||||
| r [n++] = (char) jlimit (-128.0f, 127.0f, highestRight * 127.0f); | |||||
| } | |||||
| else | |||||
| { | |||||
| l [n++] = (char) jlimit (-128.0f, 127.0f, lowestLeft * 127.0f); | |||||
| l [n++] = (char) jlimit (-128.0f, 127.0f, highestLeft * 127.0f); | |||||
| } | |||||
| } | |||||
| } | |||||
| char* AudioThumbnail::getChannelData (int channel) const | |||||
| { | |||||
| AudioThumbnailDataFormat* const d = (AudioThumbnailDataFormat*) data.getData(); | |||||
| jassert (d != 0); | |||||
| if (channel >= 0 && channel < d->numChannels) | |||||
| return d->data + (channel * 2 * d->numThumbnailSamples); | |||||
| return 0; | |||||
| } | |||||
| bool AudioThumbnail::isFullyLoaded() const throw() | |||||
| { | |||||
| const AudioThumbnailDataFormat* const d = (const AudioThumbnailDataFormat*) data.getData(); | |||||
| jassert (d != 0); | |||||
| return d->numFinishedSamples >= d->totalSamples; | |||||
| } | |||||
| void AudioThumbnail::refillCache (const int numSamples, | |||||
| double startTime, | |||||
| const double timePerPixel) | |||||
| { | |||||
| const AudioThumbnailDataFormat* const d = (const AudioThumbnailDataFormat*) data.getData(); | |||||
| jassert (d != 0); | |||||
| if (numSamples <= 0 | |||||
| || timePerPixel <= 0.0 | |||||
| || d->sampleRate <= 0) | |||||
| { | |||||
| numSamplesCached = 0; | |||||
| cacheNeedsRefilling = true; | |||||
| return; | |||||
| } | |||||
| if (numSamples == numSamplesCached | |||||
| && numChannelsCached == d->numChannels | |||||
| && startTime == cachedStart | |||||
| && timePerPixel == cachedTimePerPixel | |||||
| && ! cacheNeedsRefilling) | |||||
| { | |||||
| return; | |||||
| } | |||||
| numSamplesCached = numSamples; | |||||
| numChannelsCached = d->numChannels; | |||||
| cachedStart = startTime; | |||||
| cachedTimePerPixel = timePerPixel; | |||||
| cachedLevels.ensureSize (2 * numChannelsCached * numSamples); | |||||
| const bool needExtraDetail = (timePerPixel * d->sampleRate <= d->samplesPerThumbSample); | |||||
| const ScopedLock sl (readerLock); | |||||
| cacheNeedsRefilling = false; | |||||
| if (needExtraDetail && reader == 0) | |||||
| reader = createReader(); | |||||
| if (reader != 0 && timePerPixel * d->sampleRate <= d->samplesPerThumbSample) | |||||
| { | |||||
| startTimer (timeBeforeDeletingReader); | |||||
| char* cacheData = (char*) cachedLevels.getData(); | |||||
| int sample = roundDoubleToInt (startTime * d->sampleRate); | |||||
| for (int i = numSamples; --i >= 0;) | |||||
| { | |||||
| const int nextSample = roundDoubleToInt ((startTime + timePerPixel) * d->sampleRate); | |||||
| if (sample >= 0) | |||||
| { | |||||
| if (sample >= reader->lengthInSamples) | |||||
| break; | |||||
| float lmin, lmax, rmin, rmax; | |||||
| reader->readMaxLevels (sample, | |||||
| jmax (1, nextSample - sample), | |||||
| lmin, lmax, rmin, rmax); | |||||
| cacheData[0] = (char) jlimit (-128, 127, roundFloatToInt (lmin * 127.0f)); | |||||
| cacheData[1] = (char) jlimit (-128, 127, roundFloatToInt (lmax * 127.0f)); | |||||
| if (numChannelsCached > 1) | |||||
| { | |||||
| cacheData[2] = (char) jlimit (-128, 127, roundFloatToInt (rmin * 127.0f)); | |||||
| cacheData[3] = (char) jlimit (-128, 127, roundFloatToInt (rmax * 127.0f)); | |||||
| } | |||||
| cacheData += 2 * numChannelsCached; | |||||
| } | |||||
| startTime += timePerPixel; | |||||
| sample = nextSample; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int channelNum = 0; channelNum < numChannelsCached; ++channelNum) | |||||
| { | |||||
| char* const data = getChannelData (channelNum); | |||||
| char* cacheData = ((char*) cachedLevels.getData()) + channelNum * 2; | |||||
| const double timeToThumbSampleFactor = d->sampleRate / (double) d->samplesPerThumbSample; | |||||
| startTime = cachedStart; | |||||
| int sample = roundDoubleToInt (startTime * timeToThumbSampleFactor); | |||||
| const int numFinished = (int) (d->numFinishedSamples / d->samplesPerThumbSample); | |||||
| for (int i = numSamples; --i >= 0;) | |||||
| { | |||||
| const int nextSample = roundDoubleToInt ((startTime + timePerPixel) * timeToThumbSampleFactor); | |||||
| if (sample >= 0 && data != 0) | |||||
| { | |||||
| char mx = -128; | |||||
| char mn = 127; | |||||
| while (sample <= nextSample) | |||||
| { | |||||
| if (sample >= numFinished) | |||||
| break; | |||||
| const int n = sample << 1; | |||||
| const char sampMin = data [n]; | |||||
| const char sampMax = data [n + 1]; | |||||
| if (sampMin < mn) | |||||
| mn = sampMin; | |||||
| if (sampMax > mx) | |||||
| mx = sampMax; | |||||
| ++sample; | |||||
| } | |||||
| if (mn <= mx) | |||||
| { | |||||
| cacheData[0] = mn; | |||||
| cacheData[1] = mx; | |||||
| } | |||||
| else | |||||
| { | |||||
| cacheData[0] = 1; | |||||
| cacheData[1] = 0; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| cacheData[0] = 1; | |||||
| cacheData[1] = 0; | |||||
| } | |||||
| cacheData += numChannelsCached * 2; | |||||
| startTime += timePerPixel; | |||||
| sample = nextSample; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| void AudioThumbnail::drawChannel (Graphics& g, | |||||
| int x, int y, int w, int h, | |||||
| double startTime, | |||||
| double endTime, | |||||
| int channelNum, | |||||
| const float verticalZoomFactor) | |||||
| { | |||||
| refillCache (w, startTime, (endTime - startTime) / w); | |||||
| if (numSamplesCached >= w | |||||
| && channelNum >= 0 | |||||
| && channelNum < numChannelsCached) | |||||
| { | |||||
| const float topY = (float) y; | |||||
| const float bottomY = topY + h; | |||||
| const float midY = topY + h * 0.5f; | |||||
| const float vscale = verticalZoomFactor * h / 256.0f; | |||||
| const Rectangle clip (g.getClipBounds()); | |||||
| const int skipLeft = jlimit (0, w, clip.getX() - x); | |||||
| w -= skipLeft; | |||||
| x += skipLeft; | |||||
| const char* cacheData = ((const char*) cachedLevels.getData()) | |||||
| + (channelNum << 1) | |||||
| + skipLeft * (numChannelsCached << 1); | |||||
| while (--w >= 0) | |||||
| { | |||||
| const char mn = cacheData[0]; | |||||
| const char mx = cacheData[1]; | |||||
| cacheData += numChannelsCached << 1; | |||||
| if (mn <= mx) // if the wrong way round, signifies that the sample's not yet known | |||||
| g.drawLine ((float) x, jmax (midY - mx * vscale - 0.3f, topY), | |||||
| (float) x, jmin (midY - mn * vscale + 0.3f, bottomY)); | |||||
| ++x; | |||||
| if (x >= clip.getRight()) | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| END_JUCE_NAMESPACE | |||||
| @@ -0,0 +1,189 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #ifndef __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__ | |||||
| #define __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__ | |||||
| #include "../../threads/juce_TimeSliceThread.h" | |||||
| #include "../../io/streams/juce_InputSource.h" | |||||
| #include "../../io/streams/juce_OutputStream.h" | |||||
| #include "../../events/juce_ChangeBroadcaster.h" | |||||
| #include "../../events/juce_Timer.h" | |||||
| #include "../../gui/graphics/contexts/juce_Graphics.h" | |||||
| #include "juce_AudioFormatReader.h" | |||||
| #include "juce_AudioFormatManager.h" | |||||
| class AudioThumbnailCache; | |||||
| //============================================================================== | |||||
| /** | |||||
| Makes it easy to quickly draw scaled views of the waveform shape of an | |||||
| audio file. | |||||
| To use this class, just create an AudioThumbNail class for the file you want | |||||
| to draw, call setSource to tell it which file or resource to use, then call | |||||
| drawChannel() to draw it. | |||||
| The class will asynchronously scan the wavefile to create its scaled-down view, | |||||
| so you should make your UI repaint itself as this data comes in. To do this, the | |||||
| AudioThumbnail is a ChangeBroadcaster, and will broadcast a message when its | |||||
| listeners should repaint themselves. | |||||
| The thumbnail stores an internal low-res version of the wave data, and this can | |||||
| be loaded and saved to avoid having to scan the file again. | |||||
| @see AudioThumbnailCache | |||||
| */ | |||||
| class JUCE_API AudioThumbnail : public ChangeBroadcaster, | |||||
| public TimeSliceClient, | |||||
| private Timer | |||||
| { | |||||
| public: | |||||
| //============================================================================== | |||||
| /** Creates an audio thumbnail. | |||||
| @param sourceSamplesPerThumbnailSample when creating a stored, low-res version | |||||
| of the audio data, this is the scale at which it should be done | |||||
| @param formatManagerToUse the audio format manager that is used to open the file | |||||
| @param cacheToUse an instance of an AudioThumbnailCache - this provides a background | |||||
| thread and storage that is used to by the thumbnail, and the cache | |||||
| object can be shared between multiple thumbnails | |||||
| */ | |||||
| AudioThumbnail (const int sourceSamplesPerThumbnailSample, | |||||
| AudioFormatManager& formatManagerToUse, | |||||
| AudioThumbnailCache& cacheToUse); | |||||
| /** Destructor. */ | |||||
| ~AudioThumbnail(); | |||||
| //============================================================================== | |||||
| /** Specifies the file or stream that contains the audio file. | |||||
| For a file, just call | |||||
| @code | |||||
| setSource (new FileInputSource (file)) | |||||
| @endcode | |||||
| You can pass a zero in here to clear the thumbnail. | |||||
| The source that is passed in will be deleted by this object when it is no | |||||
| longer needed | |||||
| */ | |||||
| void setSource (InputSource* const newSource); | |||||
| /** Reloads the low res thumbnail data from an input stream. | |||||
| The thumb will automatically attempt to reload itself from its | |||||
| AudioThumbnailCache. | |||||
| */ | |||||
| void loadFrom (InputStream& input); | |||||
| /** Saves the low res thumbnail data to an output stream. | |||||
| The thumb will automatically attempt to save itself to its | |||||
| AudioThumbnailCache after it finishes scanning the wave file. | |||||
| */ | |||||
| void saveTo (OutputStream& output) const; | |||||
| //============================================================================== | |||||
| /** Returns the number of channels in the file. | |||||
| */ | |||||
| int getNumChannels() const throw(); | |||||
| /** Returns the length of the audio file. | |||||
| */ | |||||
| double getTotalLength() const throw(); | |||||
| /** Renders the waveform shape for a channel. | |||||
| The waveform will be drawn within the specified rectangle, where startTime | |||||
| and endTime specify the times within the audio file that should be positioned | |||||
| at the left and right edges of the rectangle. | |||||
| The waveform will be scaled vertically so that a full-volume sample will fill | |||||
| the rectangle vertically, but you can also specify an extra vertical scale factor | |||||
| with the verticalZoomFactor parameter. | |||||
| */ | |||||
| void drawChannel (Graphics& g, | |||||
| int x, int y, int w, int h, | |||||
| double startTime, | |||||
| double endTime, | |||||
| int channelNum, | |||||
| const float verticalZoomFactor); | |||||
| /** Returns true if the low res preview is fully generated. | |||||
| */ | |||||
| bool isFullyLoaded() const throw(); | |||||
| //============================================================================== | |||||
| /** @internal */ | |||||
| bool useTimeSlice(); | |||||
| /** @internal */ | |||||
| void timerCallback(); | |||||
| //============================================================================== | |||||
| juce_UseDebuggingNewOperator | |||||
| private: | |||||
| AudioFormatManager& formatManagerToUse; | |||||
| AudioThumbnailCache& cache; | |||||
| InputSource* source; | |||||
| CriticalSection readerLock; | |||||
| AudioFormatReader* reader; | |||||
| MemoryBlock data, cachedLevels; | |||||
| int orginalSamplesPerThumbnailSample; | |||||
| int numChannelsCached, numSamplesCached; | |||||
| double cachedStart, cachedTimePerPixel; | |||||
| bool cacheNeedsRefilling; | |||||
| void clear(); | |||||
| AudioFormatReader* createReader() const; | |||||
| void generateSection (AudioFormatReader& reader, | |||||
| int64 startSample, | |||||
| int numSamples); | |||||
| char* getChannelData (int channel) const; | |||||
| void refillCache (const int numSamples, | |||||
| double startTime, | |||||
| const double timePerPixel); | |||||
| friend class AudioThumbnailCache; | |||||
| // true if it needs more callbacks from the readNextBlockFromAudioFile() method | |||||
| bool initialiseFromAudioFile (AudioFormatReader& reader); | |||||
| // returns true if more needs to be read | |||||
| bool readNextBlockFromAudioFile (AudioFormatReader& reader); | |||||
| }; | |||||
| #endif // __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__ | |||||
| @@ -0,0 +1,139 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #include "../../core/juce_StandardHeader.h" | |||||
| BEGIN_JUCE_NAMESPACE | |||||
| #include "juce_AudioThumbnailCache.h" | |||||
| #include "../../io/streams/juce_MemoryInputStream.h" | |||||
| #include "../../io/streams/juce_MemoryOutputStream.h" | |||||
| //============================================================================== | |||||
| struct ThumbnailCacheEntry | |||||
| { | |||||
| int64 hash; | |||||
| uint32 lastUsed; | |||||
| MemoryBlock data; | |||||
| juce_UseDebuggingNewOperator | |||||
| }; | |||||
| //============================================================================== | |||||
| AudioThumbnailCache::AudioThumbnailCache (const int maxNumThumbsToStore_) | |||||
| : TimeSliceThread (T("thumb cache")), | |||||
| maxNumThumbsToStore (maxNumThumbsToStore_) | |||||
| { | |||||
| startThread (2); | |||||
| } | |||||
| AudioThumbnailCache::~AudioThumbnailCache() | |||||
| { | |||||
| } | |||||
| bool AudioThumbnailCache::loadThumb (AudioThumbnail& thumb, const int64 hashCode) | |||||
| { | |||||
| for (int i = thumbs.size(); --i >= 0;) | |||||
| { | |||||
| if (thumbs[i]->hash == hashCode) | |||||
| { | |||||
| MemoryInputStream in ((const char*) thumbs[i]->data.getData(), | |||||
| thumbs[i]->data.getSize(), | |||||
| false); | |||||
| thumb.loadFrom (in); | |||||
| thumbs[i]->lastUsed = Time::getMillisecondCounter(); | |||||
| return true; | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| void AudioThumbnailCache::storeThumb (const AudioThumbnail& thumb, | |||||
| const int64 hashCode) | |||||
| { | |||||
| MemoryOutputStream out; | |||||
| thumb.saveTo (out); | |||||
| ThumbnailCacheEntry* te = 0; | |||||
| for (int i = thumbs.size(); --i >= 0;) | |||||
| { | |||||
| if (thumbs[i]->hash == hashCode) | |||||
| { | |||||
| te = thumbs[i]; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (te == 0) | |||||
| { | |||||
| te = new ThumbnailCacheEntry(); | |||||
| te->hash = hashCode; | |||||
| if (thumbs.size() < maxNumThumbsToStore) | |||||
| { | |||||
| thumbs.add (te); | |||||
| } | |||||
| else | |||||
| { | |||||
| int oldest = 0; | |||||
| unsigned int oldestTime = Time::getMillisecondCounter() + 1; | |||||
| int i; | |||||
| for (i = thumbs.size(); --i >= 0;) | |||||
| if (thumbs[i]->lastUsed < oldestTime) | |||||
| oldest = i; | |||||
| thumbs.set (i, te); | |||||
| } | |||||
| } | |||||
| te->lastUsed = Time::getMillisecondCounter(); | |||||
| te->data.setSize (0); | |||||
| te->data.append (out.getData(), out.getDataSize()); | |||||
| } | |||||
| void AudioThumbnailCache::clear() | |||||
| { | |||||
| thumbs.clear(); | |||||
| } | |||||
| //============================================================================== | |||||
| void AudioThumbnailCache::addThumbnail (AudioThumbnail* const thumb) | |||||
| { | |||||
| addTimeSliceClient (thumb); | |||||
| } | |||||
| void AudioThumbnailCache::removeThumbnail (AudioThumbnail* const thumb) | |||||
| { | |||||
| removeTimeSliceClient (thumb); | |||||
| } | |||||
| END_JUCE_NAMESPACE | |||||
| @@ -0,0 +1,92 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #ifndef __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__ | |||||
| #define __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__ | |||||
| #include "juce_AudioThumbnail.h" | |||||
| struct ThumbnailCacheEntry; | |||||
| //============================================================================== | |||||
| /** | |||||
| An instance of this class is used to manage multiple AudioThumbnail objects. | |||||
| The cache runs a single background thread that is shared by all the thumbnails | |||||
| that need it, and it maintains a set of low-res previews in memory, to avoid | |||||
| having to re-scan audio files too often. | |||||
| @see AudioThumbnail | |||||
| */ | |||||
| class JUCE_API AudioThumbnailCache : public TimeSliceThread | |||||
| { | |||||
| public: | |||||
| //============================================================================== | |||||
| /** Creates a cache object. | |||||
| The maxNumThumbsToStore parameter lets you specify how many previews should | |||||
| be kept in memory at once. | |||||
| */ | |||||
| AudioThumbnailCache (const int maxNumThumbsToStore); | |||||
| /** Destructor. */ | |||||
| ~AudioThumbnailCache(); | |||||
| //============================================================================== | |||||
| /** Clears out any stored thumbnails. | |||||
| */ | |||||
| void clear(); | |||||
| /** Reloads the specified thumb if this cache contains the appropriate stored | |||||
| data. | |||||
| This is called automatically by the AudioThumbnail class, so you shouldn't | |||||
| normally need to call it directly. | |||||
| */ | |||||
| bool loadThumb (AudioThumbnail& thumb, const int64 hashCode); | |||||
| /** Stores the cachable data from the specified thumb in this cache. | |||||
| This is called automatically by the AudioThumbnail class, so you shouldn't | |||||
| normally need to call it directly. | |||||
| */ | |||||
| void storeThumb (const AudioThumbnail& thumb, const int64 hashCode); | |||||
| //============================================================================== | |||||
| juce_UseDebuggingNewOperator | |||||
| private: | |||||
| //============================================================================== | |||||
| OwnedArray <ThumbnailCacheEntry> thumbs; | |||||
| int maxNumThumbsToStore; | |||||
| friend class AudioThumbnail; | |||||
| void addThumbnail (AudioThumbnail* const thumb); | |||||
| void removeThumbnail (AudioThumbnail* const thumb); | |||||
| }; | |||||
| #endif // __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__ | |||||
| @@ -0,0 +1,554 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #include "../../../juce_Config.h" | |||||
| #ifdef _MSC_VER | |||||
| #include <windows.h> | |||||
| #endif | |||||
| #if JUCE_USE_FLAC | |||||
| #include "../../core/juce_StandardHeader.h" | |||||
| #ifdef _MSC_VER | |||||
| #pragma warning (disable : 4505) | |||||
| #pragma warning (push) | |||||
| #endif | |||||
| namespace FlacNamespace | |||||
| { | |||||
| #if JUCE_INCLUDE_FLAC_CODE | |||||
| #define FLAC__NO_DLL 1 | |||||
| #if ! defined (SIZE_MAX) | |||||
| #define SIZE_MAX 0xffffffff | |||||
| #endif | |||||
| #define __STDC_LIMIT_MACROS 1 | |||||
| #include "flac/all.h" | |||||
| #include "flac/libFLAC/bitmath.c" | |||||
| #include "flac/libFLAC/bitreader.c" | |||||
| #include "flac/libFLAC/bitwriter.c" | |||||
| #include "flac/libFLAC/cpu.c" | |||||
| #include "flac/libFLAC/crc.c" | |||||
| #include "flac/libFLAC/fixed.c" | |||||
| #include "flac/libFLAC/float.c" | |||||
| #include "flac/libFLAC/format.c" | |||||
| #include "flac/libFLAC/lpc_flac.c" | |||||
| #include "flac/libFLAC/md5.c" | |||||
| #include "flac/libFLAC/memory.c" | |||||
| #include "flac/libFLAC/stream_decoder.c" | |||||
| #include "flac/libFLAC/stream_encoder.c" | |||||
| #include "flac/libFLAC/stream_encoder_framing.c" | |||||
| #include "flac/libFLAC/window_flac.c" | |||||
| #else | |||||
| #include <FLAC/all.h> | |||||
| #endif | |||||
| } | |||||
| #ifdef _MSC_VER | |||||
| #pragma warning (pop) | |||||
| #endif | |||||
| BEGIN_JUCE_NAMESPACE | |||||
| #include "juce_FlacAudioFormat.h" | |||||
| #include "../../text/juce_LocalisedStrings.h" | |||||
| using namespace FlacNamespace; | |||||
| //============================================================================== | |||||
| #define flacFormatName TRANS("FLAC file") | |||||
| static const tchar* const flacExtensions[] = { T(".flac"), 0 }; | |||||
| //============================================================================== | |||||
| class FlacReader : public AudioFormatReader | |||||
| { | |||||
| FLAC__StreamDecoder* decoder; | |||||
| AudioSampleBuffer reservoir; | |||||
| int reservoirStart, samplesInReservoir; | |||||
| bool ok, scanningForLength; | |||||
| public: | |||||
| //============================================================================== | |||||
| FlacReader (InputStream* const in) | |||||
| : AudioFormatReader (in, flacFormatName), | |||||
| reservoir (2, 0), | |||||
| reservoirStart (0), | |||||
| samplesInReservoir (0), | |||||
| scanningForLength (false) | |||||
| { | |||||
| using namespace FlacNamespace; | |||||
| lengthInSamples = 0; | |||||
| decoder = FLAC__stream_decoder_new(); | |||||
| ok = FLAC__stream_decoder_init_stream (decoder, | |||||
| readCallback_, seekCallback_, tellCallback_, lengthCallback_, | |||||
| eofCallback_, writeCallback_, metadataCallback_, errorCallback_, | |||||
| (void*) this) == FLAC__STREAM_DECODER_INIT_STATUS_OK; | |||||
| if (ok) | |||||
| { | |||||
| FLAC__stream_decoder_process_until_end_of_metadata (decoder); | |||||
| if (lengthInSamples == 0 && sampleRate > 0) | |||||
| { | |||||
| // the length hasn't been stored in the metadata, so we'll need to | |||||
| // work it out the length the hard way, by scanning the whole file.. | |||||
| scanningForLength = true; | |||||
| FLAC__stream_decoder_process_until_end_of_stream (decoder); | |||||
| scanningForLength = false; | |||||
| const int64 tempLength = lengthInSamples; | |||||
| FLAC__stream_decoder_reset (decoder); | |||||
| FLAC__stream_decoder_process_until_end_of_metadata (decoder); | |||||
| lengthInSamples = tempLength; | |||||
| } | |||||
| } | |||||
| } | |||||
| ~FlacReader() | |||||
| { | |||||
| FLAC__stream_decoder_delete (decoder); | |||||
| } | |||||
| void useMetadata (const FLAC__StreamMetadata_StreamInfo& info) | |||||
| { | |||||
| sampleRate = info.sample_rate; | |||||
| bitsPerSample = info.bits_per_sample; | |||||
| lengthInSamples = (unsigned int) info.total_samples; | |||||
| numChannels = info.channels; | |||||
| reservoir.setSize (numChannels, 2 * info.max_blocksize, false, false, true); | |||||
| } | |||||
| // returns the number of samples read | |||||
| bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, | |||||
| int64 startSampleInFile, int numSamples) | |||||
| { | |||||
| using namespace FlacNamespace; | |||||
| if (! ok) | |||||
| return false; | |||||
| while (numSamples > 0) | |||||
| { | |||||
| if (startSampleInFile >= reservoirStart | |||||
| && startSampleInFile < reservoirStart + samplesInReservoir) | |||||
| { | |||||
| const int num = (int) jmin ((int64) numSamples, | |||||
| reservoirStart + samplesInReservoir - startSampleInFile); | |||||
| jassert (num > 0); | |||||
| for (int i = jmin (numDestChannels, reservoir.getNumChannels()); --i >= 0;) | |||||
| if (destSamples[i] != 0) | |||||
| memcpy (destSamples[i] + startOffsetInDestBuffer, | |||||
| reservoir.getSampleData (i, (int) (startSampleInFile - reservoirStart)), | |||||
| sizeof (int) * num); | |||||
| startOffsetInDestBuffer += num; | |||||
| startSampleInFile += num; | |||||
| numSamples -= num; | |||||
| } | |||||
| else | |||||
| { | |||||
| if (startSampleInFile < reservoirStart | |||||
| || startSampleInFile > reservoirStart + jmax (samplesInReservoir, 511)) | |||||
| { | |||||
| if (startSampleInFile >= (int) lengthInSamples) | |||||
| { | |||||
| samplesInReservoir = 0; | |||||
| break; | |||||
| } | |||||
| // had some problems with flac crashing if the read pos is aligned more | |||||
| // accurately than this. Probably fixed in newer versions of the library, though. | |||||
| reservoirStart = (int) (startSampleInFile & ~511); | |||||
| FLAC__stream_decoder_seek_absolute (decoder, (FLAC__uint64) reservoirStart); | |||||
| } | |||||
| else | |||||
| { | |||||
| reservoirStart += samplesInReservoir; | |||||
| } | |||||
| samplesInReservoir = 0; | |||||
| FLAC__stream_decoder_process_single (decoder); | |||||
| if (samplesInReservoir == 0) | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (numSamples > 0) | |||||
| { | |||||
| for (int i = numDestChannels; --i >= 0;) | |||||
| if (destSamples[i] != 0) | |||||
| zeromem (destSamples[i] + startOffsetInDestBuffer, | |||||
| sizeof (int) * numSamples); | |||||
| } | |||||
| return true; | |||||
| } | |||||
| void useSamples (const FLAC__int32* const buffer[], int numSamples) | |||||
| { | |||||
| if (scanningForLength) | |||||
| { | |||||
| lengthInSamples += numSamples; | |||||
| } | |||||
| else | |||||
| { | |||||
| if (numSamples > reservoir.getNumSamples()) | |||||
| reservoir.setSize (numChannels, numSamples, false, false, true); | |||||
| const int bitsToShift = 32 - bitsPerSample; | |||||
| for (int i = 0; i < (int) numChannels; ++i) | |||||
| { | |||||
| const FLAC__int32* src = buffer[i]; | |||||
| int n = i; | |||||
| while (src == 0 && n > 0) | |||||
| src = buffer [--n]; | |||||
| if (src != 0) | |||||
| { | |||||
| int* dest = (int*) reservoir.getSampleData(i); | |||||
| for (int j = 0; j < numSamples; ++j) | |||||
| dest[j] = src[j] << bitsToShift; | |||||
| } | |||||
| } | |||||
| samplesInReservoir = numSamples; | |||||
| } | |||||
| } | |||||
| //============================================================================== | |||||
| static FLAC__StreamDecoderReadStatus readCallback_ (const FLAC__StreamDecoder*, FLAC__byte buffer[], size_t* bytes, void* client_data) | |||||
| { | |||||
| *bytes = (unsigned int) ((const FlacReader*) client_data)->input->read (buffer, (int) *bytes); | |||||
| return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; | |||||
| } | |||||
| static FLAC__StreamDecoderSeekStatus seekCallback_ (const FLAC__StreamDecoder*, FLAC__uint64 absolute_byte_offset, void* client_data) | |||||
| { | |||||
| ((const FlacReader*) client_data)->input->setPosition ((int) absolute_byte_offset); | |||||
| return FLAC__STREAM_DECODER_SEEK_STATUS_OK; | |||||
| } | |||||
| static FLAC__StreamDecoderTellStatus tellCallback_ (const FLAC__StreamDecoder*, FLAC__uint64* absolute_byte_offset, void* client_data) | |||||
| { | |||||
| *absolute_byte_offset = ((const FlacReader*) client_data)->input->getPosition(); | |||||
| return FLAC__STREAM_DECODER_TELL_STATUS_OK; | |||||
| } | |||||
| static FLAC__StreamDecoderLengthStatus lengthCallback_ (const FLAC__StreamDecoder*, FLAC__uint64* stream_length, void* client_data) | |||||
| { | |||||
| *stream_length = ((const FlacReader*) client_data)->input->getTotalLength(); | |||||
| return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; | |||||
| } | |||||
| static FLAC__bool eofCallback_ (const FLAC__StreamDecoder*, void* client_data) | |||||
| { | |||||
| return ((const FlacReader*) client_data)->input->isExhausted(); | |||||
| } | |||||
| static FLAC__StreamDecoderWriteStatus writeCallback_ (const FLAC__StreamDecoder*, | |||||
| const FLAC__Frame* frame, | |||||
| const FLAC__int32* const buffer[], | |||||
| void* client_data) | |||||
| { | |||||
| ((FlacReader*) client_data)->useSamples (buffer, frame->header.blocksize); | |||||
| return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; | |||||
| } | |||||
| static void metadataCallback_ (const FLAC__StreamDecoder*, | |||||
| const FLAC__StreamMetadata* metadata, | |||||
| void* client_data) | |||||
| { | |||||
| ((FlacReader*) client_data)->useMetadata (metadata->data.stream_info); | |||||
| } | |||||
| static void errorCallback_ (const FLAC__StreamDecoder*, FLAC__StreamDecoderErrorStatus, void*) | |||||
| { | |||||
| } | |||||
| juce_UseDebuggingNewOperator | |||||
| }; | |||||
| //============================================================================== | |||||
| class FlacWriter : public AudioFormatWriter | |||||
| { | |||||
| FLAC__StreamEncoder* encoder; | |||||
| MemoryBlock temp; | |||||
| public: | |||||
| bool ok; | |||||
| //============================================================================== | |||||
| FlacWriter (OutputStream* const out, | |||||
| const double sampleRate, | |||||
| const int numChannels, | |||||
| const int bitsPerSample_) | |||||
| : AudioFormatWriter (out, flacFormatName, | |||||
| sampleRate, | |||||
| numChannels, | |||||
| bitsPerSample_) | |||||
| { | |||||
| using namespace FlacNamespace; | |||||
| encoder = FLAC__stream_encoder_new(); | |||||
| FLAC__stream_encoder_set_do_mid_side_stereo (encoder, numChannels == 2); | |||||
| FLAC__stream_encoder_set_loose_mid_side_stereo (encoder, numChannels == 2); | |||||
| FLAC__stream_encoder_set_channels (encoder, numChannels); | |||||
| FLAC__stream_encoder_set_bits_per_sample (encoder, jmin (24, bitsPerSample)); | |||||
| FLAC__stream_encoder_set_sample_rate (encoder, (unsigned int) sampleRate); | |||||
| FLAC__stream_encoder_set_blocksize (encoder, 2048); | |||||
| FLAC__stream_encoder_set_do_escape_coding (encoder, true); | |||||
| ok = FLAC__stream_encoder_init_stream (encoder, | |||||
| encodeWriteCallback, encodeSeekCallback, | |||||
| encodeTellCallback, encodeMetadataCallback, | |||||
| (void*) this) == FLAC__STREAM_ENCODER_INIT_STATUS_OK; | |||||
| } | |||||
| ~FlacWriter() | |||||
| { | |||||
| if (ok) | |||||
| { | |||||
| FLAC__stream_encoder_finish (encoder); | |||||
| output->flush(); | |||||
| } | |||||
| else | |||||
| { | |||||
| output = 0; // to stop the base class deleting this, as it needs to be returned | |||||
| // to the caller of createWriter() | |||||
| } | |||||
| FLAC__stream_encoder_delete (encoder); | |||||
| } | |||||
| //============================================================================== | |||||
| bool write (const int** samplesToWrite, int numSamples) | |||||
| { | |||||
| if (! ok) | |||||
| return false; | |||||
| int* buf[3]; | |||||
| const int bitsToShift = 32 - bitsPerSample; | |||||
| if (bitsToShift > 0) | |||||
| { | |||||
| const int numChannels = (samplesToWrite[1] == 0) ? 1 : 2; | |||||
| temp.setSize (sizeof (int) * numSamples * numChannels); | |||||
| buf[0] = (int*) temp.getData(); | |||||
| buf[1] = buf[0] + numSamples; | |||||
| buf[2] = 0; | |||||
| for (int i = numChannels; --i >= 0;) | |||||
| { | |||||
| if (samplesToWrite[i] != 0) | |||||
| { | |||||
| for (int j = 0; j < numSamples; ++j) | |||||
| buf [i][j] = (samplesToWrite [i][j] >> bitsToShift); | |||||
| } | |||||
| } | |||||
| samplesToWrite = (const int**) buf; | |||||
| } | |||||
| return FLAC__stream_encoder_process (encoder, | |||||
| (const FLAC__int32**) samplesToWrite, | |||||
| numSamples) != 0; | |||||
| } | |||||
| bool writeData (const void* const data, const int size) const | |||||
| { | |||||
| return output->write (data, size); | |||||
| } | |||||
| static void packUint32 (FLAC__uint32 val, FLAC__byte* b, const int bytes) | |||||
| { | |||||
| b += bytes; | |||||
| for (int i = 0; i < bytes; ++i) | |||||
| { | |||||
| *(--b) = (FLAC__byte) (val & 0xff); | |||||
| val >>= 8; | |||||
| } | |||||
| } | |||||
| void writeMetaData (const FLAC__StreamMetadata* metadata) | |||||
| { | |||||
| using namespace FlacNamespace; | |||||
| const FLAC__StreamMetadata_StreamInfo& info = metadata->data.stream_info; | |||||
| unsigned char buffer [FLAC__STREAM_METADATA_STREAMINFO_LENGTH]; | |||||
| const unsigned int channelsMinus1 = info.channels - 1; | |||||
| const unsigned int bitsMinus1 = info.bits_per_sample - 1; | |||||
| packUint32 (info.min_blocksize, buffer, 2); | |||||
| packUint32 (info.max_blocksize, buffer + 2, 2); | |||||
| packUint32 (info.min_framesize, buffer + 4, 3); | |||||
| packUint32 (info.max_framesize, buffer + 7, 3); | |||||
| buffer[10] = (uint8) ((info.sample_rate >> 12) & 0xff); | |||||
| buffer[11] = (uint8) ((info.sample_rate >> 4) & 0xff); | |||||
| buffer[12] = (uint8) (((info.sample_rate & 0x0f) << 4) | (channelsMinus1 << 1) | (bitsMinus1 >> 4)); | |||||
| buffer[13] = (FLAC__byte) (((bitsMinus1 & 0x0f) << 4) | (unsigned int) ((info.total_samples >> 32) & 0x0f)); | |||||
| packUint32 ((FLAC__uint32) info.total_samples, buffer + 14, 4); | |||||
| memcpy (buffer + 18, info.md5sum, 16); | |||||
| const bool ok = output->setPosition (4); | |||||
| (void) ok; | |||||
| // if this fails, you've given it an output stream that can't seek! It needs | |||||
| // to be able to seek back to write the header | |||||
| jassert (ok); | |||||
| output->writeIntBigEndian (FLAC__STREAM_METADATA_STREAMINFO_LENGTH); | |||||
| output->write (buffer, FLAC__STREAM_METADATA_STREAMINFO_LENGTH); | |||||
| } | |||||
| //============================================================================== | |||||
| static FLAC__StreamEncoderWriteStatus encodeWriteCallback (const FLAC__StreamEncoder*, | |||||
| const FLAC__byte buffer[], | |||||
| size_t bytes, | |||||
| unsigned int /*samples*/, | |||||
| unsigned int /*current_frame*/, | |||||
| void* client_data) | |||||
| { | |||||
| using namespace FlacNamespace; | |||||
| return ((FlacWriter*) client_data)->writeData (buffer, (int) bytes) | |||||
| ? FLAC__STREAM_ENCODER_WRITE_STATUS_OK | |||||
| : FLAC__STREAM_ENCODER_WRITE_STATUS_FATAL_ERROR; | |||||
| } | |||||
| static FLAC__StreamEncoderSeekStatus encodeSeekCallback (const FLAC__StreamEncoder*, FLAC__uint64, void*) | |||||
| { | |||||
| return FLAC__STREAM_ENCODER_SEEK_STATUS_UNSUPPORTED; | |||||
| } | |||||
| static FLAC__StreamEncoderTellStatus encodeTellCallback (const FLAC__StreamEncoder*, FLAC__uint64*, void*) | |||||
| { | |||||
| return FLAC__STREAM_ENCODER_TELL_STATUS_UNSUPPORTED; | |||||
| } | |||||
| static void encodeMetadataCallback (const FLAC__StreamEncoder*, | |||||
| const FLAC__StreamMetadata* metadata, | |||||
| void* client_data) | |||||
| { | |||||
| ((FlacWriter*) client_data)->writeMetaData (metadata); | |||||
| } | |||||
| juce_UseDebuggingNewOperator | |||||
| }; | |||||
| //============================================================================== | |||||
| FlacAudioFormat::FlacAudioFormat() | |||||
| : AudioFormat (flacFormatName, (const tchar**) flacExtensions) | |||||
| { | |||||
| } | |||||
| FlacAudioFormat::~FlacAudioFormat() | |||||
| { | |||||
| } | |||||
| const Array <int> FlacAudioFormat::getPossibleSampleRates() | |||||
| { | |||||
| const int rates[] = { 22050, 32000, 44100, 48000, 88200, 96000, 0 }; | |||||
| return Array <int> (rates); | |||||
| } | |||||
| const Array <int> FlacAudioFormat::getPossibleBitDepths() | |||||
| { | |||||
| const int depths[] = { 16, 24, 0 }; | |||||
| return Array <int> (depths); | |||||
| } | |||||
| bool FlacAudioFormat::canDoStereo() | |||||
| { | |||||
| return true; | |||||
| } | |||||
| bool FlacAudioFormat::canDoMono() | |||||
| { | |||||
| return true; | |||||
| } | |||||
| bool FlacAudioFormat::isCompressed() | |||||
| { | |||||
| return true; | |||||
| } | |||||
| AudioFormatReader* FlacAudioFormat::createReaderFor (InputStream* in, | |||||
| const bool deleteStreamIfOpeningFails) | |||||
| { | |||||
| FlacReader* r = new FlacReader (in); | |||||
| if (r->sampleRate == 0) | |||||
| { | |||||
| if (! deleteStreamIfOpeningFails) | |||||
| r->input = 0; | |||||
| deleteAndZero (r); | |||||
| } | |||||
| return r; | |||||
| } | |||||
| AudioFormatWriter* FlacAudioFormat::createWriterFor (OutputStream* out, | |||||
| double sampleRate, | |||||
| unsigned int numberOfChannels, | |||||
| int bitsPerSample, | |||||
| const StringPairArray& /*metadataValues*/, | |||||
| int /*qualityOptionIndex*/) | |||||
| { | |||||
| if (getPossibleBitDepths().contains (bitsPerSample)) | |||||
| { | |||||
| FlacWriter* w = new FlacWriter (out, | |||||
| sampleRate, | |||||
| numberOfChannels, | |||||
| bitsPerSample); | |||||
| if (! w->ok) | |||||
| deleteAndZero (w); | |||||
| return w; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| END_JUCE_NAMESPACE | |||||
| #endif | |||||
| @@ -0,0 +1,75 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #ifndef __JUCE_FLACAUDIOFORMAT_JUCEHEADER__ | |||||
| #define __JUCE_FLACAUDIOFORMAT_JUCEHEADER__ | |||||
| #include "juce_AudioFormat.h" // (must keep this outside the conditional define) | |||||
| #if JUCE_USE_FLAC || defined (DOXYGEN) | |||||
| //============================================================================== | |||||
| /** | |||||
| Reads and writes the lossless-compression FLAC audio format. | |||||
| To compile this, you'll need to set the JUCE_USE_FLAC flag in juce_Config.h, | |||||
| and make sure your include search path and library search path are set up to find | |||||
| the FLAC header files and static libraries. | |||||
| @see AudioFormat | |||||
| */ | |||||
| class JUCE_API FlacAudioFormat : public AudioFormat | |||||
| { | |||||
| public: | |||||
| //============================================================================== | |||||
| FlacAudioFormat(); | |||||
| ~FlacAudioFormat(); | |||||
| //============================================================================== | |||||
| const Array <int> getPossibleSampleRates(); | |||||
| const Array <int> getPossibleBitDepths(); | |||||
| bool canDoStereo(); | |||||
| bool canDoMono(); | |||||
| bool isCompressed(); | |||||
| //============================================================================== | |||||
| AudioFormatReader* createReaderFor (InputStream* sourceStream, | |||||
| const bool deleteStreamIfOpeningFails); | |||||
| AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, | |||||
| double sampleRateToUse, | |||||
| unsigned int numberOfChannels, | |||||
| int bitsPerSample, | |||||
| const StringPairArray& metadataValues, | |||||
| int qualityOptionIndex); | |||||
| //============================================================================== | |||||
| juce_UseDebuggingNewOperator | |||||
| }; | |||||
| #endif | |||||
| #endif // __JUCE_FLACAUDIOFORMAT_JUCEHEADER__ | |||||
| @@ -0,0 +1,504 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #include "../../../juce_Config.h" | |||||
| #if JUCE_USE_OGGVORBIS | |||||
| #include "../../core/juce_StandardHeader.h" | |||||
| #if JUCE_MAC | |||||
| #define __MACOSX__ 1 | |||||
| #endif | |||||
| namespace OggVorbisNamespace | |||||
| { | |||||
| #if JUCE_INCLUDE_OGGVORBIS_CODE | |||||
| #include "oggvorbis/vorbisenc.h" | |||||
| #include "oggvorbis/codec.h" | |||||
| #include "oggvorbis/vorbisfile.h" | |||||
| #include "oggvorbis/bitwise.c" | |||||
| #include "oggvorbis/framing.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/analysis.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/bitrate.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/block.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/codebook.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/envelope.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/floor0.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/floor1.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/info.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/lpc.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/lsp.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/mapping0.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/mdct.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/psy.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/registry.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/res0.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/sharedbook.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/smallft.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/synthesis.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/vorbisenc.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/vorbisfile.c" | |||||
| #include "oggvorbis/libvorbis-1.1.2/lib/window.c" | |||||
| #else | |||||
| #include <vorbis/vorbisenc.h> | |||||
| #include <vorbis/codec.h> | |||||
| #include <vorbis/vorbisfile.h> | |||||
| #endif | |||||
| } | |||||
| BEGIN_JUCE_NAMESPACE | |||||
| #include "juce_OggVorbisAudioFormat.h" | |||||
| #include "../../application/juce_Application.h" | |||||
| #include "../../core/juce_Random.h" | |||||
| #include "../../io/files/juce_FileInputStream.h" | |||||
| #include "../../text/juce_LocalisedStrings.h" | |||||
| using namespace OggVorbisNamespace; | |||||
| //============================================================================== | |||||
| #define oggFormatName TRANS("Ogg-Vorbis file") | |||||
| static const tchar* const oggExtensions[] = { T(".ogg"), 0 }; | |||||
| //============================================================================== | |||||
| class OggReader : public AudioFormatReader | |||||
| { | |||||
| OggVorbis_File ovFile; | |||||
| ov_callbacks callbacks; | |||||
| AudioSampleBuffer reservoir; | |||||
| int reservoirStart, samplesInReservoir; | |||||
| public: | |||||
| //============================================================================== | |||||
| OggReader (InputStream* const inp) | |||||
| : AudioFormatReader (inp, oggFormatName), | |||||
| reservoir (2, 4096), | |||||
| reservoirStart (0), | |||||
| samplesInReservoir (0) | |||||
| { | |||||
| sampleRate = 0; | |||||
| usesFloatingPointData = true; | |||||
| callbacks.read_func = &oggReadCallback; | |||||
| callbacks.seek_func = &oggSeekCallback; | |||||
| callbacks.close_func = &oggCloseCallback; | |||||
| callbacks.tell_func = &oggTellCallback; | |||||
| const int err = ov_open_callbacks (input, &ovFile, 0, 0, callbacks); | |||||
| if (err == 0) | |||||
| { | |||||
| vorbis_info* info = ov_info (&ovFile, -1); | |||||
| lengthInSamples = (uint32) ov_pcm_total (&ovFile, -1); | |||||
| numChannels = info->channels; | |||||
| bitsPerSample = 16; | |||||
| sampleRate = info->rate; | |||||
| reservoir.setSize (numChannels, | |||||
| (int) jmin (lengthInSamples, (int64) reservoir.getNumSamples())); | |||||
| } | |||||
| } | |||||
| ~OggReader() | |||||
| { | |||||
| ov_clear (&ovFile); | |||||
| } | |||||
| //============================================================================== | |||||
| bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, | |||||
| int64 startSampleInFile, int numSamples) | |||||
| { | |||||
| while (numSamples > 0) | |||||
| { | |||||
| const int numAvailable = reservoirStart + samplesInReservoir - startSampleInFile; | |||||
| if (startSampleInFile >= reservoirStart && numAvailable > 0) | |||||
| { | |||||
| // got a few samples overlapping, so use them before seeking.. | |||||
| const int numToUse = jmin (numSamples, numAvailable); | |||||
| for (int i = jmin (numDestChannels, reservoir.getNumChannels()); --i >= 0;) | |||||
| if (destSamples[i] != 0) | |||||
| memcpy (destSamples[i] + startOffsetInDestBuffer, | |||||
| reservoir.getSampleData (i, (int) (startSampleInFile - reservoirStart)), | |||||
| sizeof (float) * numToUse); | |||||
| startSampleInFile += numToUse; | |||||
| numSamples -= numToUse; | |||||
| startOffsetInDestBuffer += numToUse; | |||||
| if (numSamples == 0) | |||||
| break; | |||||
| } | |||||
| if (startSampleInFile < reservoirStart | |||||
| || startSampleInFile + numSamples > reservoirStart + samplesInReservoir) | |||||
| { | |||||
| // buffer miss, so refill the reservoir | |||||
| int bitStream = 0; | |||||
| reservoirStart = jmax (0, (int) startSampleInFile); | |||||
| samplesInReservoir = reservoir.getNumSamples(); | |||||
| if (reservoirStart != (int) ov_pcm_tell (&ovFile)) | |||||
| ov_pcm_seek (&ovFile, reservoirStart); | |||||
| int offset = 0; | |||||
| int numToRead = samplesInReservoir; | |||||
| while (numToRead > 0) | |||||
| { | |||||
| float** dataIn = 0; | |||||
| const int samps = ov_read_float (&ovFile, &dataIn, numToRead, &bitStream); | |||||
| if (samps == 0) | |||||
| break; | |||||
| jassert (samps <= numToRead); | |||||
| for (int i = jmin (numChannels, reservoir.getNumChannels()); --i >= 0;) | |||||
| { | |||||
| memcpy (reservoir.getSampleData (i, offset), | |||||
| dataIn[i], | |||||
| sizeof (float) * samps); | |||||
| } | |||||
| numToRead -= samps; | |||||
| offset += samps; | |||||
| } | |||||
| if (numToRead > 0) | |||||
| reservoir.clear (offset, numToRead); | |||||
| } | |||||
| } | |||||
| if (numSamples > 0) | |||||
| { | |||||
| for (int i = numDestChannels; --i >= 0;) | |||||
| if (destSamples[i] != 0) | |||||
| zeromem (destSamples[i] + startOffsetInDestBuffer, | |||||
| sizeof (int) * numSamples); | |||||
| } | |||||
| return true; | |||||
| } | |||||
| //============================================================================== | |||||
| static size_t oggReadCallback (void* ptr, size_t size, size_t nmemb, void* datasource) | |||||
| { | |||||
| return (size_t) (((InputStream*) datasource)->read (ptr, (int) (size * nmemb)) / size); | |||||
| } | |||||
| static int oggSeekCallback (void* datasource, ogg_int64_t offset, int whence) | |||||
| { | |||||
| InputStream* const in = (InputStream*) datasource; | |||||
| if (whence == SEEK_CUR) | |||||
| offset += in->getPosition(); | |||||
| else if (whence == SEEK_END) | |||||
| offset += in->getTotalLength(); | |||||
| in->setPosition (offset); | |||||
| return 0; | |||||
| } | |||||
| static int oggCloseCallback (void*) | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| static long oggTellCallback (void* datasource) | |||||
| { | |||||
| return (long) ((InputStream*) datasource)->getPosition(); | |||||
| } | |||||
| juce_UseDebuggingNewOperator | |||||
| }; | |||||
| //============================================================================== | |||||
| class OggWriter : public AudioFormatWriter | |||||
| { | |||||
| ogg_stream_state os; | |||||
| ogg_page og; | |||||
| ogg_packet op; | |||||
| vorbis_info vi; | |||||
| vorbis_comment vc; | |||||
| vorbis_dsp_state vd; | |||||
| vorbis_block vb; | |||||
| public: | |||||
| bool ok; | |||||
| //============================================================================== | |||||
| OggWriter (OutputStream* const out, | |||||
| const double sampleRate, | |||||
| const int numChannels, | |||||
| const int bitsPerSample, | |||||
| const int qualityIndex) | |||||
| : AudioFormatWriter (out, oggFormatName, | |||||
| sampleRate, | |||||
| numChannels, | |||||
| bitsPerSample) | |||||
| { | |||||
| ok = false; | |||||
| vorbis_info_init (&vi); | |||||
| if (vorbis_encode_init_vbr (&vi, | |||||
| numChannels, | |||||
| (int) sampleRate, | |||||
| jlimit (0.0f, 1.0f, qualityIndex * 0.5f)) == 0) | |||||
| { | |||||
| vorbis_comment_init (&vc); | |||||
| if (JUCEApplication::getInstance() != 0) | |||||
| vorbis_comment_add_tag (&vc, "ENCODER", | |||||
| (char*) (const char*) JUCEApplication::getInstance()->getApplicationName()); | |||||
| vorbis_analysis_init (&vd, &vi); | |||||
| vorbis_block_init (&vd, &vb); | |||||
| ogg_stream_init (&os, Random::getSystemRandom().nextInt()); | |||||
| ogg_packet header; | |||||
| ogg_packet header_comm; | |||||
| ogg_packet header_code; | |||||
| vorbis_analysis_headerout (&vd, &vc, &header, &header_comm, &header_code); | |||||
| ogg_stream_packetin (&os, &header); | |||||
| ogg_stream_packetin (&os, &header_comm); | |||||
| ogg_stream_packetin (&os, &header_code); | |||||
| for (;;) | |||||
| { | |||||
| if (ogg_stream_flush (&os, &og) == 0) | |||||
| break; | |||||
| output->write (og.header, og.header_len); | |||||
| output->write (og.body, og.body_len); | |||||
| } | |||||
| ok = true; | |||||
| } | |||||
| } | |||||
| ~OggWriter() | |||||
| { | |||||
| if (ok) | |||||
| { | |||||
| // write a zero-length packet to show ogg that we're finished.. | |||||
| write (0, 0); | |||||
| ogg_stream_clear (&os); | |||||
| vorbis_block_clear (&vb); | |||||
| vorbis_dsp_clear (&vd); | |||||
| vorbis_comment_clear (&vc); | |||||
| vorbis_info_clear (&vi); | |||||
| output->flush(); | |||||
| } | |||||
| else | |||||
| { | |||||
| vorbis_info_clear (&vi); | |||||
| output = 0; // to stop the base class deleting this, as it needs to be returned | |||||
| // to the caller of createWriter() | |||||
| } | |||||
| } | |||||
| //============================================================================== | |||||
| bool write (const int** samplesToWrite, int numSamples) | |||||
| { | |||||
| if (! ok) | |||||
| return false; | |||||
| if (numSamples > 0) | |||||
| { | |||||
| const double gain = 1.0 / 0x80000000u; | |||||
| float** const vorbisBuffer = vorbis_analysis_buffer (&vd, numSamples); | |||||
| for (int i = numChannels; --i >= 0;) | |||||
| { | |||||
| float* const dst = vorbisBuffer[i]; | |||||
| const int* const src = samplesToWrite [i]; | |||||
| if (src != 0 && dst != 0) | |||||
| { | |||||
| for (int j = 0; j < numSamples; ++j) | |||||
| dst[j] = (float) (src[j] * gain); | |||||
| } | |||||
| } | |||||
| } | |||||
| vorbis_analysis_wrote (&vd, numSamples); | |||||
| while (vorbis_analysis_blockout (&vd, &vb) == 1) | |||||
| { | |||||
| vorbis_analysis (&vb, 0); | |||||
| vorbis_bitrate_addblock (&vb); | |||||
| while (vorbis_bitrate_flushpacket (&vd, &op)) | |||||
| { | |||||
| ogg_stream_packetin (&os, &op); | |||||
| for (;;) | |||||
| { | |||||
| if (ogg_stream_pageout (&os, &og) == 0) | |||||
| break; | |||||
| output->write (og.header, og.header_len); | |||||
| output->write (og.body, og.body_len); | |||||
| if (ogg_page_eos (&og)) | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| return true; | |||||
| } | |||||
| juce_UseDebuggingNewOperator | |||||
| }; | |||||
| //============================================================================== | |||||
| OggVorbisAudioFormat::OggVorbisAudioFormat() | |||||
| : AudioFormat (oggFormatName, (const tchar**) oggExtensions) | |||||
| { | |||||
| } | |||||
| OggVorbisAudioFormat::~OggVorbisAudioFormat() | |||||
| { | |||||
| } | |||||
| const Array <int> OggVorbisAudioFormat::getPossibleSampleRates() | |||||
| { | |||||
| const int rates[] = { 22050, 32000, 44100, 48000, 0 }; | |||||
| return Array <int> (rates); | |||||
| } | |||||
| const Array <int> OggVorbisAudioFormat::getPossibleBitDepths() | |||||
| { | |||||
| Array <int> depths; | |||||
| depths.add (32); | |||||
| return depths; | |||||
| } | |||||
| bool OggVorbisAudioFormat::canDoStereo() | |||||
| { | |||||
| return true; | |||||
| } | |||||
| bool OggVorbisAudioFormat::canDoMono() | |||||
| { | |||||
| return true; | |||||
| } | |||||
| AudioFormatReader* OggVorbisAudioFormat::createReaderFor (InputStream* in, | |||||
| const bool deleteStreamIfOpeningFails) | |||||
| { | |||||
| OggReader* r = new OggReader (in); | |||||
| if (r->sampleRate == 0) | |||||
| { | |||||
| if (! deleteStreamIfOpeningFails) | |||||
| r->input = 0; | |||||
| deleteAndZero (r); | |||||
| } | |||||
| return r; | |||||
| } | |||||
| AudioFormatWriter* OggVorbisAudioFormat::createWriterFor (OutputStream* out, | |||||
| double sampleRate, | |||||
| unsigned int numChannels, | |||||
| int bitsPerSample, | |||||
| const StringPairArray& /*metadataValues*/, | |||||
| int qualityOptionIndex) | |||||
| { | |||||
| OggWriter* w = new OggWriter (out, | |||||
| sampleRate, | |||||
| numChannels, | |||||
| bitsPerSample, | |||||
| qualityOptionIndex); | |||||
| if (! w->ok) | |||||
| deleteAndZero (w); | |||||
| return w; | |||||
| } | |||||
| bool OggVorbisAudioFormat::isCompressed() | |||||
| { | |||||
| return true; | |||||
| } | |||||
| const StringArray OggVorbisAudioFormat::getQualityOptions() | |||||
| { | |||||
| StringArray s; | |||||
| s.add ("Low Quality"); | |||||
| s.add ("Medium Quality"); | |||||
| s.add ("High Quality"); | |||||
| return s; | |||||
| } | |||||
| int OggVorbisAudioFormat::estimateOggFileQuality (const File& source) | |||||
| { | |||||
| FileInputStream* const in = source.createInputStream(); | |||||
| if (in != 0) | |||||
| { | |||||
| AudioFormatReader* const r = createReaderFor (in, true); | |||||
| if (r != 0) | |||||
| { | |||||
| const int64 numSamps = r->lengthInSamples; | |||||
| delete r; | |||||
| const int64 fileNumSamps = source.getSize() / 4; | |||||
| const double ratio = numSamps / (double) fileNumSamps; | |||||
| if (ratio > 12.0) | |||||
| return 0; | |||||
| else if (ratio > 6.0) | |||||
| return 1; | |||||
| else | |||||
| return 2; | |||||
| } | |||||
| } | |||||
| return 1; | |||||
| } | |||||
| END_JUCE_NAMESPACE | |||||
| #endif | |||||
| @@ -0,0 +1,88 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #ifndef __JUCE_OGGVORBISAUDIOFORMAT_JUCEHEADER__ | |||||
| #define __JUCE_OGGVORBISAUDIOFORMAT_JUCEHEADER__ | |||||
| #include "juce_AudioFormat.h" // (must keep this outside the conditional define) | |||||
| #if JUCE_USE_OGGVORBIS || defined (DOXYGEN) | |||||
| //============================================================================== | |||||
| /** | |||||
| Reads and writes the Ogg-Vorbis audio format. | |||||
| To compile this, you'll need to set the JUCE_USE_OGGVORBIS flag in juce_Config.h, | |||||
| and make sure your include search path and library search path are set up to find | |||||
| the Vorbis and Ogg header files and static libraries. | |||||
| @see AudioFormat, | |||||
| */ | |||||
| class JUCE_API OggVorbisAudioFormat : public AudioFormat | |||||
| { | |||||
| public: | |||||
| //============================================================================== | |||||
| OggVorbisAudioFormat(); | |||||
| ~OggVorbisAudioFormat(); | |||||
| //============================================================================== | |||||
| const Array <int> getPossibleSampleRates(); | |||||
| const Array <int> getPossibleBitDepths(); | |||||
| bool canDoStereo(); | |||||
| bool canDoMono(); | |||||
| bool isCompressed(); | |||||
| const StringArray getQualityOptions(); | |||||
| //============================================================================== | |||||
| /** Tries to estimate the quality level of an ogg file based on its size. | |||||
| If it can't read the file for some reason, this will just return 1 (medium quality), | |||||
| otherwise it will return the approximate quality setting that would have been used | |||||
| to create the file. | |||||
| @see getQualityOptions | |||||
| */ | |||||
| int estimateOggFileQuality (const File& source); | |||||
| //============================================================================== | |||||
| AudioFormatReader* createReaderFor (InputStream* sourceStream, | |||||
| const bool deleteStreamIfOpeningFails); | |||||
| AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, | |||||
| double sampleRateToUse, | |||||
| unsigned int numberOfChannels, | |||||
| int bitsPerSample, | |||||
| const StringPairArray& metadataValues, | |||||
| int qualityOptionIndex); | |||||
| //============================================================================== | |||||
| juce_UseDebuggingNewOperator | |||||
| }; | |||||
| #endif | |||||
| #endif // __JUCE_OGGVORBISAUDIOFORMAT_JUCEHEADER__ | |||||
| @@ -0,0 +1,407 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #include "../../../juce_Config.h" | |||||
| #if JUCE_QUICKTIME | |||||
| #if ! defined (_WIN32) | |||||
| #include <QuickTime/Movies.h> | |||||
| #include <QuickTime/QTML.h> | |||||
| #include <QuickTime/QuickTimeComponents.h> | |||||
| #include <QuickTime/MediaHandlers.h> | |||||
| #include <QuickTime/ImageCodec.h> | |||||
| #else | |||||
| #ifdef _MSC_VER | |||||
| #pragma warning (push) | |||||
| #pragma warning (disable : 4100) | |||||
| #endif | |||||
| /* If you've got an include error here, you probably need to install the QuickTime SDK and | |||||
| add its header directory to your include path. | |||||
| Alternatively, if you don't need any QuickTime services, just turn off the JUC_QUICKTIME | |||||
| flag in juce_Config.h | |||||
| */ | |||||
| #include <Movies.h> | |||||
| #include <QTML.h> | |||||
| #include <QuickTimeComponents.h> | |||||
| #include <MediaHandlers.h> | |||||
| #include <ImageCodec.h> | |||||
| #ifdef _MSC_VER | |||||
| #pragma warning (pop) | |||||
| #endif | |||||
| #endif | |||||
| #include "../../core/juce_StandardHeader.h" | |||||
| #if ! (JUCE_MAC && JUCE_64BIT) | |||||
| BEGIN_JUCE_NAMESPACE | |||||
| #include "juce_QuickTimeAudioFormat.h" | |||||
| #include "../../text/juce_LocalisedStrings.h" | |||||
| #include "../../threads/juce_Thread.h" | |||||
| #include "../../io/network/juce_URL.h" | |||||
| bool juce_OpenQuickTimeMovieFromStream (InputStream* input, Movie& movie, Handle& dataHandle); | |||||
| #define quickTimeFormatName TRANS("QuickTime file") | |||||
| static const tchar* const quickTimeExtensions[] = { T(".mov"), T(".mp3"), T(".mp4"), 0 }; | |||||
| //============================================================================== | |||||
| class QTAudioReader : public AudioFormatReader | |||||
| { | |||||
| public: | |||||
| QTAudioReader (InputStream* const input_, const int trackNum_) | |||||
| : AudioFormatReader (input_, quickTimeFormatName), | |||||
| ok (false), | |||||
| movie (0), | |||||
| trackNum (trackNum_), | |||||
| extractor (0), | |||||
| lastSampleRead (0), | |||||
| lastThreadId (0), | |||||
| dataHandle (0) | |||||
| { | |||||
| bufferList = (AudioBufferList*) juce_calloc (256); | |||||
| #ifdef WIN32 | |||||
| if (InitializeQTML (0) != noErr) | |||||
| return; | |||||
| #endif | |||||
| if (EnterMovies() != noErr) | |||||
| return; | |||||
| bool opened = juce_OpenQuickTimeMovieFromStream (input_, movie, dataHandle); | |||||
| if (! opened) | |||||
| return; | |||||
| { | |||||
| const int numTracks = GetMovieTrackCount (movie); | |||||
| int trackCount = 0; | |||||
| for (int i = 1; i <= numTracks; ++i) | |||||
| { | |||||
| track = GetMovieIndTrack (movie, i); | |||||
| media = GetTrackMedia (track); | |||||
| OSType mediaType; | |||||
| GetMediaHandlerDescription (media, &mediaType, 0, 0); | |||||
| if (mediaType == SoundMediaType | |||||
| && trackCount++ == trackNum_) | |||||
| { | |||||
| ok = true; | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (! ok) | |||||
| return; | |||||
| ok = false; | |||||
| lengthInSamples = GetMediaDecodeDuration (media); | |||||
| usesFloatingPointData = false; | |||||
| samplesPerFrame = (int) (GetMediaDecodeDuration (media) / GetMediaSampleCount (media)); | |||||
| trackUnitsPerFrame = GetMovieTimeScale (movie) * samplesPerFrame | |||||
| / GetMediaTimeScale (media); | |||||
| OSStatus err = MovieAudioExtractionBegin (movie, 0, &extractor); | |||||
| unsigned long output_layout_size; | |||||
| err = MovieAudioExtractionGetPropertyInfo (extractor, | |||||
| kQTPropertyClass_MovieAudioExtraction_Audio, | |||||
| kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, | |||||
| 0, &output_layout_size, 0); | |||||
| if (err != noErr) | |||||
| return; | |||||
| AudioChannelLayout* const qt_audio_channel_layout | |||||
| = (AudioChannelLayout*) juce_calloc (output_layout_size); | |||||
| err = MovieAudioExtractionGetProperty (extractor, | |||||
| kQTPropertyClass_MovieAudioExtraction_Audio, | |||||
| kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, | |||||
| output_layout_size, qt_audio_channel_layout, 0); | |||||
| qt_audio_channel_layout->mChannelLayoutTag = kAudioChannelLayoutTag_Stereo; | |||||
| err = MovieAudioExtractionSetProperty (extractor, | |||||
| kQTPropertyClass_MovieAudioExtraction_Audio, | |||||
| kQTMovieAudioExtractionAudioPropertyID_AudioChannelLayout, | |||||
| sizeof (qt_audio_channel_layout), | |||||
| qt_audio_channel_layout); | |||||
| juce_free (qt_audio_channel_layout); | |||||
| err = MovieAudioExtractionGetProperty (extractor, | |||||
| kQTPropertyClass_MovieAudioExtraction_Audio, | |||||
| kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, | |||||
| sizeof (inputStreamDesc), | |||||
| &inputStreamDesc, 0); | |||||
| if (err != noErr) | |||||
| return; | |||||
| inputStreamDesc.mFormatFlags = kAudioFormatFlagIsSignedInteger | |||||
| | kAudioFormatFlagIsPacked | |||||
| | kAudioFormatFlagsNativeEndian; | |||||
| inputStreamDesc.mBitsPerChannel = sizeof (SInt16) * 8; | |||||
| inputStreamDesc.mChannelsPerFrame = jmin (2, inputStreamDesc.mChannelsPerFrame); | |||||
| inputStreamDesc.mBytesPerFrame = sizeof (SInt16) * inputStreamDesc.mChannelsPerFrame; | |||||
| inputStreamDesc.mBytesPerPacket = inputStreamDesc.mBytesPerFrame; | |||||
| err = MovieAudioExtractionSetProperty (extractor, | |||||
| kQTPropertyClass_MovieAudioExtraction_Audio, | |||||
| kQTMovieAudioExtractionAudioPropertyID_AudioStreamBasicDescription, | |||||
| sizeof (inputStreamDesc), | |||||
| &inputStreamDesc); | |||||
| if (err != noErr) | |||||
| return; | |||||
| Boolean allChannelsDiscrete = false; | |||||
| err = MovieAudioExtractionSetProperty (extractor, | |||||
| kQTPropertyClass_MovieAudioExtraction_Movie, | |||||
| kQTMovieAudioExtractionMoviePropertyID_AllChannelsDiscrete, | |||||
| sizeof (allChannelsDiscrete), | |||||
| &allChannelsDiscrete); | |||||
| if (err != noErr) | |||||
| return; | |||||
| bufferList->mNumberBuffers = 1; | |||||
| bufferList->mBuffers[0].mNumberChannels = inputStreamDesc.mChannelsPerFrame; | |||||
| bufferList->mBuffers[0].mDataByteSize = (UInt32) (samplesPerFrame * inputStreamDesc.mBytesPerFrame) + 16; | |||||
| bufferList->mBuffers[0].mData = malloc (bufferList->mBuffers[0].mDataByteSize); | |||||
| sampleRate = inputStreamDesc.mSampleRate; | |||||
| bitsPerSample = 16; | |||||
| numChannels = inputStreamDesc.mChannelsPerFrame; | |||||
| detachThread(); | |||||
| ok = true; | |||||
| } | |||||
| ~QTAudioReader() | |||||
| { | |||||
| if (dataHandle != 0) | |||||
| DisposeHandle (dataHandle); | |||||
| if (extractor != 0) | |||||
| { | |||||
| MovieAudioExtractionEnd (extractor); | |||||
| extractor = 0; | |||||
| } | |||||
| checkThreadIsAttached(); | |||||
| DisposeMovie (movie); | |||||
| juce_free (bufferList->mBuffers[0].mData); | |||||
| juce_free (bufferList); | |||||
| #if JUCE_MAC | |||||
| ExitMoviesOnThread (); | |||||
| #endif | |||||
| } | |||||
| bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, | |||||
| int64 startSampleInFile, int numSamples) | |||||
| { | |||||
| checkThreadIsAttached(); | |||||
| while (numSamples > 0) | |||||
| { | |||||
| if (! loadFrame ((int) startSampleInFile)) | |||||
| return false; | |||||
| const int numToDo = jmin (numSamples, samplesPerFrame); | |||||
| for (int j = numDestChannels; --j >= 0;) | |||||
| { | |||||
| if (destSamples[j] != 0) | |||||
| { | |||||
| const short* const src = ((const short*) bufferList->mBuffers[0].mData) + j; | |||||
| for (int i = 0; i < numToDo; ++i) | |||||
| destSamples[j][startOffsetInDestBuffer + i] = src [i << 1] << 16; | |||||
| } | |||||
| } | |||||
| startOffsetInDestBuffer += numToDo; | |||||
| startSampleInFile += numToDo; | |||||
| numSamples -= numToDo; | |||||
| } | |||||
| detachThread(); | |||||
| return true; | |||||
| } | |||||
| bool loadFrame (const int sampleNum) | |||||
| { | |||||
| if (lastSampleRead != sampleNum) | |||||
| { | |||||
| TimeRecord time; | |||||
| time.scale = (TimeScale) inputStreamDesc.mSampleRate; | |||||
| time.base = 0; | |||||
| time.value.hi = 0; | |||||
| time.value.lo = (UInt32) sampleNum; | |||||
| OSStatus err = MovieAudioExtractionSetProperty (extractor, | |||||
| kQTPropertyClass_MovieAudioExtraction_Movie, | |||||
| kQTMovieAudioExtractionMoviePropertyID_CurrentTime, | |||||
| sizeof (time), &time); | |||||
| if (err != noErr) | |||||
| return false; | |||||
| } | |||||
| bufferList->mBuffers[0].mDataByteSize = inputStreamDesc.mBytesPerFrame * samplesPerFrame; | |||||
| UInt32 outFlags = 0; | |||||
| UInt32 actualNumSamples = samplesPerFrame; | |||||
| OSStatus err = MovieAudioExtractionFillBuffer (extractor, &actualNumSamples, | |||||
| bufferList, &outFlags); | |||||
| lastSampleRead = sampleNum + samplesPerFrame; | |||||
| return err == noErr; | |||||
| } | |||||
| juce_UseDebuggingNewOperator | |||||
| bool ok; | |||||
| private: | |||||
| Movie movie; | |||||
| Media media; | |||||
| Track track; | |||||
| const int trackNum; | |||||
| double trackUnitsPerFrame; | |||||
| int samplesPerFrame; | |||||
| int lastSampleRead; | |||||
| Thread::ThreadID lastThreadId; | |||||
| MovieAudioExtractionRef extractor; | |||||
| AudioStreamBasicDescription inputStreamDesc; | |||||
| AudioBufferList* bufferList; | |||||
| Handle dataHandle; | |||||
| /*OSErr readMovieStream (long offset, long size, void* dataPtr) | |||||
| { | |||||
| input->setPosition (offset); | |||||
| input->read (dataPtr, size); | |||||
| return noErr; | |||||
| } | |||||
| static OSErr readMovieStreamProc (long offset, long size, void* dataPtr, void* userRef) | |||||
| { | |||||
| return ((QTAudioReader*) userRef)->readMovieStream (offset, size, dataPtr); | |||||
| }*/ | |||||
| //============================================================================== | |||||
| void checkThreadIsAttached() | |||||
| { | |||||
| #if JUCE_MAC | |||||
| if (Thread::getCurrentThreadId() != lastThreadId) | |||||
| EnterMoviesOnThread (0); | |||||
| AttachMovieToCurrentThread (movie); | |||||
| #endif | |||||
| } | |||||
| void detachThread() | |||||
| { | |||||
| #if JUCE_MAC | |||||
| DetachMovieFromCurrentThread (movie); | |||||
| #endif | |||||
| } | |||||
| }; | |||||
| //============================================================================== | |||||
| QuickTimeAudioFormat::QuickTimeAudioFormat() | |||||
| : AudioFormat (quickTimeFormatName, (const tchar**) quickTimeExtensions) | |||||
| { | |||||
| } | |||||
| QuickTimeAudioFormat::~QuickTimeAudioFormat() | |||||
| { | |||||
| } | |||||
| const Array <int> QuickTimeAudioFormat::getPossibleSampleRates() | |||||
| { | |||||
| return Array<int>(); | |||||
| } | |||||
| const Array <int> QuickTimeAudioFormat::getPossibleBitDepths() | |||||
| { | |||||
| return Array<int>(); | |||||
| } | |||||
| bool QuickTimeAudioFormat::canDoStereo() | |||||
| { | |||||
| return true; | |||||
| } | |||||
| bool QuickTimeAudioFormat::canDoMono() | |||||
| { | |||||
| return true; | |||||
| } | |||||
| //============================================================================== | |||||
| AudioFormatReader* QuickTimeAudioFormat::createReaderFor (InputStream* sourceStream, | |||||
| const bool deleteStreamIfOpeningFails) | |||||
| { | |||||
| QTAudioReader* r = new QTAudioReader (sourceStream, 0); | |||||
| if (! r->ok) | |||||
| { | |||||
| if (! deleteStreamIfOpeningFails) | |||||
| r->input = 0; | |||||
| deleteAndZero (r); | |||||
| } | |||||
| return r; | |||||
| } | |||||
| AudioFormatWriter* QuickTimeAudioFormat::createWriterFor (OutputStream* /*streamToWriteTo*/, | |||||
| double /*sampleRateToUse*/, | |||||
| unsigned int /*numberOfChannels*/, | |||||
| int /*bitsPerSample*/, | |||||
| const StringPairArray& /*metadataValues*/, | |||||
| int /*qualityOptionIndex*/) | |||||
| { | |||||
| jassertfalse // not yet implemented! | |||||
| return 0; | |||||
| } | |||||
| END_JUCE_NAMESPACE | |||||
| #endif | |||||
| #endif | |||||
| @@ -0,0 +1,76 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #ifndef __JUCE_QUICKTIMEAUDIOFORMAT_JUCEHEADER__ | |||||
| #define __JUCE_QUICKTIMEAUDIOFORMAT_JUCEHEADER__ | |||||
| #include "juce_AudioFormat.h" | |||||
| #if JUCE_QUICKTIME | |||||
| //============================================================================== | |||||
| /** | |||||
| Uses QuickTime to read the audio track a movie or media file. | |||||
| As well as QuickTime movies, this should also manage to open other audio | |||||
| files that quicktime can understand, like mp3, m4a, etc. | |||||
| @see AudioFormat | |||||
| */ | |||||
| class JUCE_API QuickTimeAudioFormat : public AudioFormat | |||||
| { | |||||
| public: | |||||
| //============================================================================== | |||||
| /** Creates a format object. */ | |||||
| QuickTimeAudioFormat(); | |||||
| /** Destructor. */ | |||||
| ~QuickTimeAudioFormat(); | |||||
| //============================================================================== | |||||
| const Array <int> getPossibleSampleRates(); | |||||
| const Array <int> getPossibleBitDepths(); | |||||
| bool canDoStereo(); | |||||
| bool canDoMono(); | |||||
| //============================================================================== | |||||
| AudioFormatReader* createReaderFor (InputStream* sourceStream, | |||||
| const bool deleteStreamIfOpeningFails); | |||||
| AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, | |||||
| double sampleRateToUse, | |||||
| unsigned int numberOfChannels, | |||||
| int bitsPerSample, | |||||
| const StringPairArray& metadataValues, | |||||
| int qualityOptionIndex); | |||||
| //============================================================================== | |||||
| juce_UseDebuggingNewOperator | |||||
| }; | |||||
| #endif | |||||
| #endif // __JUCE_QUICKTIMEAUDIOFORMAT_JUCEHEADER__ | |||||
| @@ -0,0 +1,863 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #include "../../core/juce_StandardHeader.h" | |||||
| BEGIN_JUCE_NAMESPACE | |||||
| #include "juce_WavAudioFormat.h" | |||||
| #include "../../io/streams/juce_BufferedInputStream.h" | |||||
| #include "../../text/juce_LocalisedStrings.h" | |||||
| #include "../../io/files/juce_FileInputStream.h" | |||||
| #include "../../io/files/juce_FileOutputStream.h" | |||||
| //============================================================================== | |||||
| #define wavFormatName TRANS("WAV file") | |||||
| static const tchar* const wavExtensions[] = { T(".wav"), T(".bwf"), 0 }; | |||||
| //============================================================================== | |||||
| const tchar* const WavAudioFormat::bwavDescription = T("bwav description"); | |||||
| const tchar* const WavAudioFormat::bwavOriginator = T("bwav originator"); | |||||
| const tchar* const WavAudioFormat::bwavOriginatorRef = T("bwav originator ref"); | |||||
| const tchar* const WavAudioFormat::bwavOriginationDate = T("bwav origination date"); | |||||
| const tchar* const WavAudioFormat::bwavOriginationTime = T("bwav origination time"); | |||||
| const tchar* const WavAudioFormat::bwavTimeReference = T("bwav time reference"); | |||||
| const tchar* const WavAudioFormat::bwavCodingHistory = T("bwav coding history"); | |||||
| const StringPairArray WavAudioFormat::createBWAVMetadata (const String& description, | |||||
| const String& originator, | |||||
| const String& originatorRef, | |||||
| const Time& date, | |||||
| const int64 timeReferenceSamples, | |||||
| const String& codingHistory) | |||||
| { | |||||
| StringPairArray m; | |||||
| m.set (bwavDescription, description); | |||||
| m.set (bwavOriginator, originator); | |||||
| m.set (bwavOriginatorRef, originatorRef); | |||||
| m.set (bwavOriginationDate, date.formatted (T("%Y-%m-%d"))); | |||||
| m.set (bwavOriginationTime, date.formatted (T("%H:%M:%S"))); | |||||
| m.set (bwavTimeReference, String (timeReferenceSamples)); | |||||
| m.set (bwavCodingHistory, codingHistory); | |||||
| return m; | |||||
| } | |||||
| //============================================================================== | |||||
| #if JUCE_MSVC | |||||
| #pragma pack (push, 1) | |||||
| #define PACKED | |||||
| #elif defined (JUCE_GCC) | |||||
| #define PACKED __attribute__((packed)) | |||||
| #else | |||||
| #define PACKED | |||||
| #endif | |||||
| struct BWAVChunk | |||||
| { | |||||
| uint8 description [256]; | |||||
| uint8 originator [32]; | |||||
| uint8 originatorRef [32]; | |||||
| uint8 originationDate [10]; | |||||
| uint8 originationTime [8]; | |||||
| uint32 timeRefLow; | |||||
| uint32 timeRefHigh; | |||||
| uint16 version; | |||||
| uint8 umid[64]; | |||||
| uint8 reserved[190]; | |||||
| uint8 codingHistory[1]; | |||||
| void copyTo (StringPairArray& values) const | |||||
| { | |||||
| values.set (WavAudioFormat::bwavDescription, String::fromUTF8 (description, 256)); | |||||
| values.set (WavAudioFormat::bwavOriginator, String::fromUTF8 (originator, 32)); | |||||
| values.set (WavAudioFormat::bwavOriginatorRef, String::fromUTF8 (originatorRef, 32)); | |||||
| values.set (WavAudioFormat::bwavOriginationDate, String::fromUTF8 (originationDate, 10)); | |||||
| values.set (WavAudioFormat::bwavOriginationTime, String::fromUTF8 (originationTime, 8)); | |||||
| const uint32 timeLow = swapIfBigEndian (timeRefLow); | |||||
| const uint32 timeHigh = swapIfBigEndian (timeRefHigh); | |||||
| const int64 time = (((int64)timeHigh) << 32) + timeLow; | |||||
| values.set (WavAudioFormat::bwavTimeReference, String (time)); | |||||
| values.set (WavAudioFormat::bwavCodingHistory, String::fromUTF8 (codingHistory)); | |||||
| } | |||||
| static MemoryBlock createFrom (const StringPairArray& values) | |||||
| { | |||||
| const int sizeNeeded = sizeof (BWAVChunk) + values [WavAudioFormat::bwavCodingHistory].copyToUTF8 (0) - 1; | |||||
| MemoryBlock data ((sizeNeeded + 3) & ~3); | |||||
| data.fillWith (0); | |||||
| BWAVChunk* b = (BWAVChunk*) data.getData(); | |||||
| // Allow these calls to overwrite an extra byte at the end, which is fine as long | |||||
| // as they get called in the right order.. | |||||
| values [WavAudioFormat::bwavDescription].copyToUTF8 (b->description, 257); | |||||
| values [WavAudioFormat::bwavOriginator].copyToUTF8 (b->originator, 33); | |||||
| values [WavAudioFormat::bwavOriginatorRef].copyToUTF8 (b->originatorRef, 33); | |||||
| values [WavAudioFormat::bwavOriginationDate].copyToUTF8 (b->originationDate, 11); | |||||
| values [WavAudioFormat::bwavOriginationTime].copyToUTF8 (b->originationTime, 9); | |||||
| const int64 time = values [WavAudioFormat::bwavTimeReference].getLargeIntValue(); | |||||
| b->timeRefLow = swapIfBigEndian ((uint32) (time & 0xffffffff)); | |||||
| b->timeRefHigh = swapIfBigEndian ((uint32) (time >> 32)); | |||||
| values [WavAudioFormat::bwavCodingHistory].copyToUTF8 (b->codingHistory); | |||||
| if (b->description[0] != 0 | |||||
| || b->originator[0] != 0 | |||||
| || b->originationDate[0] != 0 | |||||
| || b->originationTime[0] != 0 | |||||
| || b->codingHistory[0] != 0 | |||||
| || time != 0) | |||||
| { | |||||
| return data; | |||||
| } | |||||
| return MemoryBlock(); | |||||
| } | |||||
| } PACKED; | |||||
| //============================================================================== | |||||
| struct SMPLChunk | |||||
| { | |||||
| struct SampleLoop | |||||
| { | |||||
| uint32 identifier; | |||||
| uint32 type; | |||||
| uint32 start; | |||||
| uint32 end; | |||||
| uint32 fraction; | |||||
| uint32 playCount; | |||||
| } PACKED; | |||||
| uint32 manufacturer; | |||||
| uint32 product; | |||||
| uint32 samplePeriod; | |||||
| uint32 midiUnityNote; | |||||
| uint32 midiPitchFraction; | |||||
| uint32 smpteFormat; | |||||
| uint32 smpteOffset; | |||||
| uint32 numSampleLoops; | |||||
| uint32 samplerData; | |||||
| SampleLoop loops[1]; | |||||
| void copyTo (StringPairArray& values, const int totalSize) const | |||||
| { | |||||
| values.set (T("Manufacturer"), String (swapIfBigEndian (manufacturer))); | |||||
| values.set (T("Product"), String (swapIfBigEndian (product))); | |||||
| values.set (T("SamplePeriod"), String (swapIfBigEndian (samplePeriod))); | |||||
| values.set (T("MidiUnityNote"), String (swapIfBigEndian (midiUnityNote))); | |||||
| values.set (T("MidiPitchFraction"), String (swapIfBigEndian (midiPitchFraction))); | |||||
| values.set (T("SmpteFormat"), String (swapIfBigEndian (smpteFormat))); | |||||
| values.set (T("SmpteOffset"), String (swapIfBigEndian (smpteOffset))); | |||||
| values.set (T("NumSampleLoops"), String (swapIfBigEndian (numSampleLoops))); | |||||
| values.set (T("SamplerData"), String (swapIfBigEndian (samplerData))); | |||||
| for (uint32 i = 0; i < numSampleLoops; ++i) | |||||
| { | |||||
| if ((uint8*) (loops + (i + 1)) > ((uint8*) this) + totalSize) | |||||
| break; | |||||
| values.set (String::formatted (T("Loop%dIdentifier"), i), String (swapIfBigEndian (loops[i].identifier))); | |||||
| values.set (String::formatted (T("Loop%dType"), i), String (swapIfBigEndian (loops[i].type))); | |||||
| values.set (String::formatted (T("Loop%dStart"), i), String (swapIfBigEndian (loops[i].start))); | |||||
| values.set (String::formatted (T("Loop%dEnd"), i), String (swapIfBigEndian (loops[i].end))); | |||||
| values.set (String::formatted (T("Loop%dFraction"), i), String (swapIfBigEndian (loops[i].fraction))); | |||||
| values.set (String::formatted (T("Loop%dPlayCount"), i), String (swapIfBigEndian (loops[i].playCount))); | |||||
| } | |||||
| } | |||||
| } PACKED; | |||||
| #if JUCE_MSVC | |||||
| #pragma pack (pop) | |||||
| #endif | |||||
| #undef PACKED | |||||
| #undef chunkName | |||||
| #define chunkName(a) ((int) littleEndianInt(a)) | |||||
| //============================================================================== | |||||
| class WavAudioFormatReader : public AudioFormatReader | |||||
| { | |||||
| int bytesPerFrame; | |||||
| int64 dataChunkStart, dataLength; | |||||
| WavAudioFormatReader (const WavAudioFormatReader&); | |||||
| const WavAudioFormatReader& operator= (const WavAudioFormatReader&); | |||||
| public: | |||||
| int64 bwavChunkStart, bwavSize; | |||||
| //============================================================================== | |||||
| WavAudioFormatReader (InputStream* const in) | |||||
| : AudioFormatReader (in, wavFormatName), | |||||
| dataLength (0), | |||||
| bwavChunkStart (0), | |||||
| bwavSize (0) | |||||
| { | |||||
| if (input->readInt() == chunkName ("RIFF")) | |||||
| { | |||||
| const uint32 len = (uint32) input->readInt(); | |||||
| const int64 end = input->getPosition() + len; | |||||
| bool hasGotType = false; | |||||
| bool hasGotData = false; | |||||
| if (input->readInt() == chunkName ("WAVE")) | |||||
| { | |||||
| while (input->getPosition() < end | |||||
| && ! input->isExhausted()) | |||||
| { | |||||
| const int chunkType = input->readInt(); | |||||
| uint32 length = (uint32) input->readInt(); | |||||
| const int64 chunkEnd = input->getPosition() + length + (length & 1); | |||||
| if (chunkType == chunkName ("fmt ")) | |||||
| { | |||||
| // read the format chunk | |||||
| const short format = input->readShort(); | |||||
| const short numChans = input->readShort(); | |||||
| sampleRate = input->readInt(); | |||||
| const int bytesPerSec = input->readInt(); | |||||
| numChannels = numChans; | |||||
| bytesPerFrame = bytesPerSec / (int)sampleRate; | |||||
| bitsPerSample = 8 * bytesPerFrame / numChans; | |||||
| if (format == 3) | |||||
| usesFloatingPointData = true; | |||||
| else if (format != 1) | |||||
| bytesPerFrame = 0; | |||||
| hasGotType = true; | |||||
| } | |||||
| else if (chunkType == chunkName ("data")) | |||||
| { | |||||
| // get the data chunk's position | |||||
| dataLength = length; | |||||
| dataChunkStart = input->getPosition(); | |||||
| lengthInSamples = (bytesPerFrame > 0) ? (dataLength / bytesPerFrame) : 0; | |||||
| hasGotData = true; | |||||
| } | |||||
| else if (chunkType == chunkName ("bext")) | |||||
| { | |||||
| bwavChunkStart = input->getPosition(); | |||||
| bwavSize = length; | |||||
| // Broadcast-wav extension chunk.. | |||||
| BWAVChunk* const bwav = (BWAVChunk*) juce_calloc (jmax (length + 1, (int) sizeof (BWAVChunk))); | |||||
| input->read (bwav, length); | |||||
| bwav->copyTo (metadataValues); | |||||
| juce_free (bwav); | |||||
| } | |||||
| else if (chunkType == chunkName ("smpl")) | |||||
| { | |||||
| SMPLChunk* const smpl = (SMPLChunk*) juce_calloc (jmax (length + 1, (int) sizeof (SMPLChunk))); | |||||
| input->read (smpl, length); | |||||
| smpl->copyTo (metadataValues, length); | |||||
| juce_free (smpl); | |||||
| } | |||||
| else if (chunkEnd <= input->getPosition()) | |||||
| { | |||||
| break; | |||||
| } | |||||
| input->setPosition (chunkEnd); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| ~WavAudioFormatReader() | |||||
| { | |||||
| } | |||||
| //============================================================================== | |||||
| bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, | |||||
| int64 startSampleInFile, int numSamples) | |||||
| { | |||||
| numSamples = (int) jmin ((int64) numSamples, lengthInSamples - startSampleInFile); | |||||
| if (numSamples <= 0) | |||||
| return true; | |||||
| input->setPosition (dataChunkStart + startSampleInFile * bytesPerFrame); | |||||
| const int tempBufSize = 480 * 3 * 4; // (keep this a multiple of 3) | |||||
| char tempBuffer [tempBufSize]; | |||||
| while (numSamples > 0) | |||||
| { | |||||
| int* left = destSamples[0]; | |||||
| if (left != 0) | |||||
| left += startOffsetInDestBuffer; | |||||
| int* right = numDestChannels > 1 ? destSamples[1] : 0; | |||||
| if (right != 0) | |||||
| right += startOffsetInDestBuffer; | |||||
| const int numThisTime = jmin (tempBufSize / bytesPerFrame, numSamples); | |||||
| const int bytesRead = input->read (tempBuffer, numThisTime * bytesPerFrame); | |||||
| if (bytesRead < numThisTime * bytesPerFrame) | |||||
| zeromem (tempBuffer + bytesRead, numThisTime * bytesPerFrame - bytesRead); | |||||
| if (bitsPerSample == 16) | |||||
| { | |||||
| const short* src = (const short*) tempBuffer; | |||||
| if (numChannels > 1) | |||||
| { | |||||
| if (left == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| ++src; | |||||
| *right++ = (int) swapIfBigEndian ((unsigned short) *src++) << 16; | |||||
| } | |||||
| } | |||||
| else if (right == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *left++ = (int) swapIfBigEndian ((unsigned short) *src++) << 16; | |||||
| ++src; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *left++ = (int) swapIfBigEndian ((unsigned short) *src++) << 16; | |||||
| *right++ = (int) swapIfBigEndian ((unsigned short) *src++) << 16; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *left++ = (int) swapIfBigEndian ((unsigned short) *src++) << 16; | |||||
| } | |||||
| } | |||||
| } | |||||
| else if (bitsPerSample == 24) | |||||
| { | |||||
| const char* src = (const char*) tempBuffer; | |||||
| if (numChannels > 1) | |||||
| { | |||||
| if (left == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| src += 3; | |||||
| *right++ = littleEndian24Bit (src) << 8; | |||||
| src += 3; | |||||
| } | |||||
| } | |||||
| else if (right == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *left++ = littleEndian24Bit (src) << 8; | |||||
| src += 6; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = 0; i < numThisTime; ++i) | |||||
| { | |||||
| *left++ = littleEndian24Bit (src) << 8; | |||||
| src += 3; | |||||
| *right++ = littleEndian24Bit (src) << 8; | |||||
| src += 3; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = 0; i < numThisTime; ++i) | |||||
| { | |||||
| *left++ = littleEndian24Bit (src) << 8; | |||||
| src += 3; | |||||
| } | |||||
| } | |||||
| } | |||||
| else if (bitsPerSample == 32) | |||||
| { | |||||
| const unsigned int* src = (const unsigned int*) tempBuffer; | |||||
| unsigned int* l = (unsigned int*) left; | |||||
| unsigned int* r = (unsigned int*) right; | |||||
| if (numChannels > 1) | |||||
| { | |||||
| if (l == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| ++src; | |||||
| *r++ = swapIfBigEndian (*src++); | |||||
| } | |||||
| } | |||||
| else if (r == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *l++ = swapIfBigEndian (*src++); | |||||
| ++src; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *l++ = swapIfBigEndian (*src++); | |||||
| *r++ = swapIfBigEndian (*src++); | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *l++ = swapIfBigEndian (*src++); | |||||
| } | |||||
| } | |||||
| left = (int*)l; | |||||
| right = (int*)r; | |||||
| } | |||||
| else if (bitsPerSample == 8) | |||||
| { | |||||
| const unsigned char* src = (const unsigned char*) tempBuffer; | |||||
| if (numChannels > 1) | |||||
| { | |||||
| if (left == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| ++src; | |||||
| *right++ = ((int) *src++ - 128) << 24; | |||||
| } | |||||
| } | |||||
| else if (right == 0) | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *left++ = ((int) *src++ - 128) << 24; | |||||
| ++src; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *left++ = ((int) *src++ - 128) << 24; | |||||
| *right++ = ((int) *src++ - 128) << 24; | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numThisTime; --i >= 0;) | |||||
| { | |||||
| *left++ = ((int)*src++ - 128) << 24; | |||||
| } | |||||
| } | |||||
| } | |||||
| startOffsetInDestBuffer += numThisTime; | |||||
| numSamples -= numThisTime; | |||||
| } | |||||
| if (numSamples > 0) | |||||
| { | |||||
| for (int i = numDestChannels; --i >= 0;) | |||||
| if (destSamples[i] != 0) | |||||
| zeromem (destSamples[i] + startOffsetInDestBuffer, | |||||
| sizeof (int) * numSamples); | |||||
| } | |||||
| return true; | |||||
| } | |||||
| juce_UseDebuggingNewOperator | |||||
| }; | |||||
| //============================================================================== | |||||
| class WavAudioFormatWriter : public AudioFormatWriter | |||||
| { | |||||
| MemoryBlock tempBlock, bwavChunk; | |||||
| uint32 lengthInSamples, bytesWritten; | |||||
| int64 headerPosition; | |||||
| bool writeFailed; | |||||
| WavAudioFormatWriter (const WavAudioFormatWriter&); | |||||
| const WavAudioFormatWriter& operator= (const WavAudioFormatWriter&); | |||||
| void writeHeader() | |||||
| { | |||||
| const bool seekedOk = output->setPosition (headerPosition); | |||||
| (void) seekedOk; | |||||
| // if this fails, you've given it an output stream that can't seek! It needs | |||||
| // to be able to seek back to write the header | |||||
| jassert (seekedOk); | |||||
| const int bytesPerFrame = numChannels * bitsPerSample / 8; | |||||
| output->writeInt (chunkName ("RIFF")); | |||||
| output->writeInt (lengthInSamples * bytesPerFrame | |||||
| + ((bwavChunk.getSize() > 0) ? (44 + bwavChunk.getSize()) : 36)); | |||||
| output->writeInt (chunkName ("WAVE")); | |||||
| output->writeInt (chunkName ("fmt ")); | |||||
| output->writeInt (16); | |||||
| output->writeShort ((bitsPerSample < 32) ? (short) 1 /*WAVE_FORMAT_PCM*/ | |||||
| : (short) 3 /*WAVE_FORMAT_IEEE_FLOAT*/); | |||||
| output->writeShort ((short) numChannels); | |||||
| output->writeInt ((int) sampleRate); | |||||
| output->writeInt (bytesPerFrame * (int) sampleRate); | |||||
| output->writeShort ((short) bytesPerFrame); | |||||
| output->writeShort ((short) bitsPerSample); | |||||
| if (bwavChunk.getSize() > 0) | |||||
| { | |||||
| output->writeInt (chunkName ("bext")); | |||||
| output->writeInt (bwavChunk.getSize()); | |||||
| output->write (bwavChunk.getData(), bwavChunk.getSize()); | |||||
| } | |||||
| output->writeInt (chunkName ("data")); | |||||
| output->writeInt (lengthInSamples * bytesPerFrame); | |||||
| usesFloatingPointData = (bitsPerSample == 32); | |||||
| } | |||||
| public: | |||||
| //============================================================================== | |||||
| WavAudioFormatWriter (OutputStream* const out, | |||||
| const double sampleRate, | |||||
| const unsigned int numChannels_, | |||||
| const int bits, | |||||
| const StringPairArray& metadataValues) | |||||
| : AudioFormatWriter (out, | |||||
| wavFormatName, | |||||
| sampleRate, | |||||
| numChannels_, | |||||
| bits), | |||||
| lengthInSamples (0), | |||||
| bytesWritten (0), | |||||
| writeFailed (false) | |||||
| { | |||||
| if (metadataValues.size() > 0) | |||||
| bwavChunk = BWAVChunk::createFrom (metadataValues); | |||||
| headerPosition = out->getPosition(); | |||||
| writeHeader(); | |||||
| } | |||||
| ~WavAudioFormatWriter() | |||||
| { | |||||
| writeHeader(); | |||||
| } | |||||
| //============================================================================== | |||||
| bool write (const int** data, int numSamples) | |||||
| { | |||||
| if (writeFailed) | |||||
| return false; | |||||
| const int bytes = numChannels * numSamples * bitsPerSample / 8; | |||||
| tempBlock.ensureSize (bytes, false); | |||||
| char* buffer = (char*) tempBlock.getData(); | |||||
| const int* left = data[0]; | |||||
| const int* right = data[1]; | |||||
| if (right == 0) | |||||
| right = left; | |||||
| if (bitsPerSample == 16) | |||||
| { | |||||
| short* b = (short*) buffer; | |||||
| if (numChannels > 1) | |||||
| { | |||||
| for (int i = numSamples; --i >= 0;) | |||||
| { | |||||
| *b++ = (short) swapIfBigEndian ((unsigned short) (*left++ >> 16)); | |||||
| *b++ = (short) swapIfBigEndian ((unsigned short) (*right++ >> 16)); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numSamples; --i >= 0;) | |||||
| { | |||||
| *b++ = (short) swapIfBigEndian ((unsigned short) (*left++ >> 16)); | |||||
| } | |||||
| } | |||||
| } | |||||
| else if (bitsPerSample == 24) | |||||
| { | |||||
| char* b = (char*) buffer; | |||||
| if (numChannels > 1) | |||||
| { | |||||
| for (int i = numSamples; --i >= 0;) | |||||
| { | |||||
| littleEndian24BitToChars ((*left++) >> 8, b); | |||||
| b += 3; | |||||
| littleEndian24BitToChars ((*right++) >> 8, b); | |||||
| b += 3; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numSamples; --i >= 0;) | |||||
| { | |||||
| littleEndian24BitToChars ((*left++) >> 8, b); | |||||
| b += 3; | |||||
| } | |||||
| } | |||||
| } | |||||
| else if (bitsPerSample == 32) | |||||
| { | |||||
| unsigned int* b = (unsigned int*) buffer; | |||||
| if (numChannels > 1) | |||||
| { | |||||
| for (int i = numSamples; --i >= 0;) | |||||
| { | |||||
| *b++ = swapIfBigEndian ((unsigned int) *left++); | |||||
| *b++ = swapIfBigEndian ((unsigned int) *right++); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numSamples; --i >= 0;) | |||||
| { | |||||
| *b++ = swapIfBigEndian ((unsigned int) *left++); | |||||
| } | |||||
| } | |||||
| } | |||||
| else if (bitsPerSample == 8) | |||||
| { | |||||
| unsigned char* b = (unsigned char*) buffer; | |||||
| if (numChannels > 1) | |||||
| { | |||||
| for (int i = numSamples; --i >= 0;) | |||||
| { | |||||
| *b++ = (unsigned char) (128 + (*left++ >> 24)); | |||||
| *b++ = (unsigned char) (128 + (*right++ >> 24)); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for (int i = numSamples; --i >= 0;) | |||||
| { | |||||
| *b++ = (unsigned char) (128 + (*left++ >> 24)); | |||||
| } | |||||
| } | |||||
| } | |||||
| if (bytesWritten + bytes >= (uint32) 0xfff00000 | |||||
| || ! output->write (buffer, bytes)) | |||||
| { | |||||
| // failed to write to disk, so let's try writing the header. | |||||
| // If it's just run out of disk space, then if it does manage | |||||
| // to write the header, we'll still have a useable file.. | |||||
| writeHeader(); | |||||
| writeFailed = true; | |||||
| return false; | |||||
| } | |||||
| else | |||||
| { | |||||
| bytesWritten += bytes; | |||||
| lengthInSamples += numSamples; | |||||
| return true; | |||||
| } | |||||
| } | |||||
| juce_UseDebuggingNewOperator | |||||
| }; | |||||
| //============================================================================== | |||||
| WavAudioFormat::WavAudioFormat() | |||||
| : AudioFormat (wavFormatName, (const tchar**) wavExtensions) | |||||
| { | |||||
| } | |||||
| WavAudioFormat::~WavAudioFormat() | |||||
| { | |||||
| } | |||||
| const Array <int> WavAudioFormat::getPossibleSampleRates() | |||||
| { | |||||
| const int rates[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400, 192000, 0 }; | |||||
| return Array <int> (rates); | |||||
| } | |||||
| const Array <int> WavAudioFormat::getPossibleBitDepths() | |||||
| { | |||||
| const int depths[] = { 8, 16, 24, 32, 0 }; | |||||
| return Array <int> (depths); | |||||
| } | |||||
| bool WavAudioFormat::canDoStereo() | |||||
| { | |||||
| return true; | |||||
| } | |||||
| bool WavAudioFormat::canDoMono() | |||||
| { | |||||
| return true; | |||||
| } | |||||
| AudioFormatReader* WavAudioFormat::createReaderFor (InputStream* sourceStream, | |||||
| const bool deleteStreamIfOpeningFails) | |||||
| { | |||||
| WavAudioFormatReader* r = new WavAudioFormatReader (sourceStream); | |||||
| if (r->sampleRate == 0) | |||||
| { | |||||
| if (! deleteStreamIfOpeningFails) | |||||
| r->input = 0; | |||||
| deleteAndZero (r); | |||||
| } | |||||
| return r; | |||||
| } | |||||
| AudioFormatWriter* WavAudioFormat::createWriterFor (OutputStream* out, | |||||
| double sampleRate, | |||||
| unsigned int numChannels, | |||||
| int bitsPerSample, | |||||
| const StringPairArray& metadataValues, | |||||
| int /*qualityOptionIndex*/) | |||||
| { | |||||
| if (getPossibleBitDepths().contains (bitsPerSample)) | |||||
| { | |||||
| return new WavAudioFormatWriter (out, | |||||
| sampleRate, | |||||
| numChannels, | |||||
| bitsPerSample, | |||||
| metadataValues); | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| static bool juce_slowCopyOfWavFileWithNewMetadata (const File& file, const StringPairArray& metadata) | |||||
| { | |||||
| bool ok = false; | |||||
| WavAudioFormat wav; | |||||
| const File dest (file.getNonexistentSibling()); | |||||
| OutputStream* outStream = dest.createOutputStream(); | |||||
| if (outStream != 0) | |||||
| { | |||||
| AudioFormatReader* reader = wav.createReaderFor (file.createInputStream(), true); | |||||
| if (reader != 0) | |||||
| { | |||||
| AudioFormatWriter* writer = wav.createWriterFor (outStream, reader->sampleRate, | |||||
| reader->numChannels, reader->bitsPerSample, | |||||
| metadata, 0); | |||||
| if (writer != 0) | |||||
| { | |||||
| ok = writer->writeFromAudioReader (*reader, 0, -1); | |||||
| outStream = 0; | |||||
| delete writer; | |||||
| } | |||||
| delete reader; | |||||
| } | |||||
| delete outStream; | |||||
| } | |||||
| if (ok) | |||||
| ok = dest.moveFileTo (file); | |||||
| if (! ok) | |||||
| dest.deleteFile(); | |||||
| return ok; | |||||
| } | |||||
| bool WavAudioFormat::replaceMetadataInFile (const File& wavFile, const StringPairArray& newMetadata) | |||||
| { | |||||
| WavAudioFormatReader* reader = (WavAudioFormatReader*) createReaderFor (wavFile.createInputStream(), true); | |||||
| if (reader != 0) | |||||
| { | |||||
| const int64 bwavPos = reader->bwavChunkStart; | |||||
| const int64 bwavSize = reader->bwavSize; | |||||
| delete reader; | |||||
| if (bwavSize > 0) | |||||
| { | |||||
| MemoryBlock chunk = BWAVChunk::createFrom (newMetadata); | |||||
| if (chunk.getSize() <= bwavSize) | |||||
| { | |||||
| // the new one will fit in the space available, so write it directly.. | |||||
| const int64 oldSize = wavFile.getSize(); | |||||
| FileOutputStream* out = wavFile.createOutputStream(); | |||||
| out->setPosition (bwavPos); | |||||
| out->write (chunk.getData(), chunk.getSize()); | |||||
| out->setPosition (oldSize); | |||||
| delete out; | |||||
| jassert (wavFile.getSize() == oldSize); | |||||
| return true; | |||||
| } | |||||
| } | |||||
| } | |||||
| return juce_slowCopyOfWavFileWithNewMetadata (wavFile, newMetadata); | |||||
| } | |||||
| END_JUCE_NAMESPACE | |||||
| @@ -0,0 +1,151 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| #ifndef __JUCE_WAVAUDIOFORMAT_JUCEHEADER__ | |||||
| #define __JUCE_WAVAUDIOFORMAT_JUCEHEADER__ | |||||
| #include "juce_AudioFormat.h" | |||||
| //============================================================================== | |||||
| /** | |||||
| Reads and Writes WAV format audio files. | |||||
| @see AudioFormat | |||||
| */ | |||||
| class JUCE_API WavAudioFormat : public AudioFormat | |||||
| { | |||||
| public: | |||||
| //============================================================================== | |||||
| /** Creates a format object. */ | |||||
| WavAudioFormat(); | |||||
| /** Destructor. */ | |||||
| ~WavAudioFormat(); | |||||
| //============================================================================== | |||||
| /** Metadata property name used by wav readers and writers for adding | |||||
| a BWAV chunk to the file. | |||||
| @see AudioFormatReader::metadataValues, createWriterFor | |||||
| */ | |||||
| static const tchar* const bwavDescription; | |||||
| /** Metadata property name used by wav readers and writers for adding | |||||
| a BWAV chunk to the file. | |||||
| @see AudioFormatReader::metadataValues, createWriterFor | |||||
| */ | |||||
| static const tchar* const bwavOriginator; | |||||
| /** Metadata property name used by wav readers and writers for adding | |||||
| a BWAV chunk to the file. | |||||
| @see AudioFormatReader::metadataValues, createWriterFor | |||||
| */ | |||||
| static const tchar* const bwavOriginatorRef; | |||||
| /** Metadata property name used by wav readers and writers for adding | |||||
| a BWAV chunk to the file. | |||||
| Date format is: yyyy-mm-dd | |||||
| @see AudioFormatReader::metadataValues, createWriterFor | |||||
| */ | |||||
| static const tchar* const bwavOriginationDate; | |||||
| /** Metadata property name used by wav readers and writers for adding | |||||
| a BWAV chunk to the file. | |||||
| Time format is: hh-mm-ss | |||||
| @see AudioFormatReader::metadataValues, createWriterFor | |||||
| */ | |||||
| static const tchar* const bwavOriginationTime; | |||||
| /** Metadata property name used by wav readers and writers for adding | |||||
| a BWAV chunk to the file. | |||||
| This is the number of samples from the start of an edit that the | |||||
| file is supposed to begin at. Seems like an obvious mistake to | |||||
| only allow a file to occur in an edit once, but that's the way | |||||
| it is.. | |||||
| @see AudioFormatReader::metadataValues, createWriterFor | |||||
| */ | |||||
| static const tchar* const bwavTimeReference; | |||||
| /** Metadata property name used by wav readers and writers for adding | |||||
| a BWAV chunk to the file. | |||||
| This is a | |||||
| @see AudioFormatReader::metadataValues, createWriterFor | |||||
| */ | |||||
| static const tchar* const bwavCodingHistory; | |||||
| /** Utility function to fill out the appropriate metadata for a BWAV file. | |||||
| This just makes it easier than using the property names directly, and it | |||||
| fills out the time and date in the right format. | |||||
| */ | |||||
| static const StringPairArray createBWAVMetadata (const String& description, | |||||
| const String& originator, | |||||
| const String& originatorRef, | |||||
| const Time& dateAndTime, | |||||
| const int64 timeReferenceSamples, | |||||
| const String& codingHistory); | |||||
| //============================================================================== | |||||
| const Array <int> getPossibleSampleRates(); | |||||
| const Array <int> getPossibleBitDepths(); | |||||
| bool canDoStereo(); | |||||
| bool canDoMono(); | |||||
| //============================================================================== | |||||
| AudioFormatReader* createReaderFor (InputStream* sourceStream, | |||||
| const bool deleteStreamIfOpeningFails); | |||||
| AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, | |||||
| double sampleRateToUse, | |||||
| unsigned int numberOfChannels, | |||||
| int bitsPerSample, | |||||
| const StringPairArray& metadataValues, | |||||
| int qualityOptionIndex); | |||||
| //============================================================================== | |||||
| /** Utility function to replace the metadata in a wav file with a new set of values. | |||||
| If possible, this cheats by overwriting just the metadata region of the file, rather | |||||
| than by copying the whole file again. | |||||
| */ | |||||
| bool replaceMetadataInFile (const File& wavFile, const StringPairArray& newMetadata); | |||||
| //============================================================================== | |||||
| juce_UseDebuggingNewOperator | |||||
| }; | |||||
| #endif // __JUCE_WAVAUDIOFORMAT_JUCEHEADER__ | |||||
| @@ -0,0 +1,47 @@ | |||||
| ===================================================================== | |||||
| I've incorporated Ogg-Vorbis directly into the Juce codebase because it makes | |||||
| things much easier than having to make all your builds link correctly to | |||||
| the appropriate libraries on every different platform. | |||||
| I've made minimal changes to the Ogg-Vorbis code - just tweaked a few include | |||||
| paths to make it build smoothly, and added some headers to allow you to exclude | |||||
| it from the build. | |||||
| ===================================================================== | |||||
| The following license is the BSD-style license that comes with the | |||||
| Ogg-Vorbis distribution, and which applies just to the header files I've | |||||
| included in this directory. For more info, and to get the rest of the | |||||
| distribution, visit the Ogg-Vorbis homepage: www.vorbis.com | |||||
| ===================================================================== | |||||
| Copyright (c) 2002-2004 Xiph.org Foundation | |||||
| 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 Xiph.org Foundation 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 FOUNDATION | |||||
| 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. | |||||
| @@ -0,0 +1,789 @@ | |||||
| /******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * | |||||
| * by the Xiph.Org Foundation http://www.xiph.org/ * | |||||
| * * | |||||
| ******************************************************************** | |||||
| function: packing variable sized words into an octet stream | |||||
| last mod: $Id: bitwise.c,v 1.1 2007/06/07 17:48:18 jules_rms Exp $ | |||||
| ********************************************************************/ | |||||
| /* We're 'LSb' endian; if we write a word but read individual bits, | |||||
| then we'll read the lsb first */ | |||||
| #include "juce_OggVorbisHeader.h" | |||||
| #if JUCE_USE_OGGVORBIS | |||||
| #include <string.h> | |||||
| #include <stdlib.h> | |||||
| #include "ogg.h" | |||||
| #define BUFFER_INCREMENT 256 | |||||
| static const unsigned long mask[]= | |||||
| {0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f, | |||||
| 0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff, | |||||
| 0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff, | |||||
| 0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff, | |||||
| 0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff, | |||||
| 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff, | |||||
| 0x3fffffff,0x7fffffff,0xffffffff }; | |||||
| static const unsigned int mask8B[]= | |||||
| {0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff}; | |||||
| void oggpack_writeinit(oggpack_buffer *b){ | |||||
| memset(b,0,sizeof(*b)); | |||||
| b->ptr=b->buffer=(unsigned char*) _ogg_malloc(BUFFER_INCREMENT); | |||||
| b->buffer[0]='\0'; | |||||
| b->storage=BUFFER_INCREMENT; | |||||
| } | |||||
| void oggpackB_writeinit(oggpack_buffer *b){ | |||||
| oggpack_writeinit(b); | |||||
| } | |||||
| void oggpack_writetrunc(oggpack_buffer *b,long bits){ | |||||
| long bytes=bits>>3; | |||||
| bits-=bytes*8; | |||||
| b->ptr=b->buffer+bytes; | |||||
| b->endbit=bits; | |||||
| b->endbyte=bytes; | |||||
| *b->ptr&=mask[bits]; | |||||
| } | |||||
| void oggpackB_writetrunc(oggpack_buffer *b,long bits){ | |||||
| long bytes=bits>>3; | |||||
| bits-=bytes*8; | |||||
| b->ptr=b->buffer+bytes; | |||||
| b->endbit=bits; | |||||
| b->endbyte=bytes; | |||||
| *b->ptr&=mask8B[bits]; | |||||
| } | |||||
| /* Takes only up to 32 bits. */ | |||||
| void oggpack_write(oggpack_buffer *b,unsigned long value,int bits){ | |||||
| if(b->endbyte+4>=b->storage){ | |||||
| b->buffer=(unsigned char*) _ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT); | |||||
| b->storage+=BUFFER_INCREMENT; | |||||
| b->ptr=b->buffer+b->endbyte; | |||||
| } | |||||
| value&=mask[bits]; | |||||
| bits+=b->endbit; | |||||
| b->ptr[0]|=value<<b->endbit; | |||||
| if(bits>=8){ | |||||
| b->ptr[1]=(unsigned char)(value>>(8-b->endbit)); | |||||
| if(bits>=16){ | |||||
| b->ptr[2]=(unsigned char)(value>>(16-b->endbit)); | |||||
| if(bits>=24){ | |||||
| b->ptr[3]=(unsigned char)(value>>(24-b->endbit)); | |||||
| if(bits>=32){ | |||||
| if(b->endbit) | |||||
| b->ptr[4]=(unsigned char)(value>>(32-b->endbit)); | |||||
| else | |||||
| b->ptr[4]=0; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| b->endbyte+=bits/8; | |||||
| b->ptr+=bits/8; | |||||
| b->endbit=bits&7; | |||||
| } | |||||
| /* Takes only up to 32 bits. */ | |||||
| void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits){ | |||||
| if(b->endbyte+4>=b->storage){ | |||||
| b->buffer=(unsigned char*) _ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT); | |||||
| b->storage+=BUFFER_INCREMENT; | |||||
| b->ptr=b->buffer+b->endbyte; | |||||
| } | |||||
| value=(value&mask[bits])<<(32-bits); | |||||
| bits+=b->endbit; | |||||
| b->ptr[0]|=value>>(24+b->endbit); | |||||
| if(bits>=8){ | |||||
| b->ptr[1]=(unsigned char)(value>>(16+b->endbit)); | |||||
| if(bits>=16){ | |||||
| b->ptr[2]=(unsigned char)(value>>(8+b->endbit)); | |||||
| if(bits>=24){ | |||||
| b->ptr[3]=(unsigned char)(value>>(b->endbit)); | |||||
| if(bits>=32){ | |||||
| if(b->endbit) | |||||
| b->ptr[4]=(unsigned char)(value<<(8-b->endbit)); | |||||
| else | |||||
| b->ptr[4]=0; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| b->endbyte+=bits/8; | |||||
| b->ptr+=bits/8; | |||||
| b->endbit=bits&7; | |||||
| } | |||||
| void oggpack_writealign(oggpack_buffer *b){ | |||||
| int bits=8-b->endbit; | |||||
| if(bits<8) | |||||
| oggpack_write(b,0,bits); | |||||
| } | |||||
| void oggpackB_writealign(oggpack_buffer *b){ | |||||
| int bits=8-b->endbit; | |||||
| if(bits<8) | |||||
| oggpackB_write(b,0,bits); | |||||
| } | |||||
| static void oggpack_writecopy_helper(oggpack_buffer *b, | |||||
| void *source, | |||||
| long bits, | |||||
| void (*w)(oggpack_buffer *, | |||||
| unsigned long, | |||||
| int), | |||||
| int msb){ | |||||
| unsigned char *ptr=(unsigned char *)source; | |||||
| long bytes=bits/8; | |||||
| bits-=bytes*8; | |||||
| if(b->endbit){ | |||||
| int i; | |||||
| /* unaligned copy. Do it the hard way. */ | |||||
| for(i=0;i<bytes;i++) | |||||
| w(b,(unsigned long)(ptr[i]),8); | |||||
| }else{ | |||||
| /* aligned block copy */ | |||||
| if(b->endbyte+bytes+1>=b->storage){ | |||||
| b->storage=b->endbyte+bytes+BUFFER_INCREMENT; | |||||
| b->buffer=(unsigned char*) _ogg_realloc(b->buffer,b->storage); | |||||
| b->ptr=b->buffer+b->endbyte; | |||||
| } | |||||
| memmove(b->ptr,source,bytes); | |||||
| b->ptr+=bytes; | |||||
| b->endbyte+=bytes; | |||||
| *b->ptr=0; | |||||
| } | |||||
| if(bits){ | |||||
| if(msb) | |||||
| w(b,(unsigned long)(ptr[bytes]>>(8-bits)),bits); | |||||
| else | |||||
| w(b,(unsigned long)(ptr[bytes]),bits); | |||||
| } | |||||
| } | |||||
| void oggpack_writecopy(oggpack_buffer *b,void *source,long bits){ | |||||
| oggpack_writecopy_helper(b,source,bits,oggpack_write,0); | |||||
| } | |||||
| void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits){ | |||||
| oggpack_writecopy_helper(b,source,bits,oggpackB_write,1); | |||||
| } | |||||
| void oggpack_reset(oggpack_buffer *b){ | |||||
| b->ptr=b->buffer; | |||||
| b->buffer[0]=0; | |||||
| b->endbit=b->endbyte=0; | |||||
| } | |||||
| void oggpackB_reset(oggpack_buffer *b){ | |||||
| oggpack_reset(b); | |||||
| } | |||||
| void oggpack_writeclear(oggpack_buffer *b){ | |||||
| _ogg_free(b->buffer); | |||||
| memset(b,0,sizeof(*b)); | |||||
| } | |||||
| void oggpackB_writeclear(oggpack_buffer *b){ | |||||
| oggpack_writeclear(b); | |||||
| } | |||||
| void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){ | |||||
| memset(b,0,sizeof(*b)); | |||||
| b->buffer=b->ptr=buf; | |||||
| b->storage=bytes; | |||||
| } | |||||
| void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){ | |||||
| oggpack_readinit(b,buf,bytes); | |||||
| } | |||||
| /* Read in bits without advancing the bitptr; bits <= 32 */ | |||||
| long oggpack_look(oggpack_buffer *b,int bits){ | |||||
| unsigned long ret; | |||||
| unsigned long m=mask[bits]; | |||||
| bits+=b->endbit; | |||||
| if(b->endbyte+4>=b->storage){ | |||||
| /* not the main path */ | |||||
| if(b->endbyte*8+bits>b->storage*8)return(-1); | |||||
| } | |||||
| ret=b->ptr[0]>>b->endbit; | |||||
| if(bits>8){ | |||||
| ret|=b->ptr[1]<<(8-b->endbit); | |||||
| if(bits>16){ | |||||
| ret|=b->ptr[2]<<(16-b->endbit); | |||||
| if(bits>24){ | |||||
| ret|=b->ptr[3]<<(24-b->endbit); | |||||
| if(bits>32 && b->endbit) | |||||
| ret|=b->ptr[4]<<(32-b->endbit); | |||||
| } | |||||
| } | |||||
| } | |||||
| return(m&ret); | |||||
| } | |||||
| /* Read in bits without advancing the bitptr; bits <= 32 */ | |||||
| long oggpackB_look(oggpack_buffer *b,int bits){ | |||||
| unsigned long ret; | |||||
| int m=32-bits; | |||||
| bits+=b->endbit; | |||||
| if(b->endbyte+4>=b->storage){ | |||||
| /* not the main path */ | |||||
| if(b->endbyte*8+bits>b->storage*8)return(-1); | |||||
| } | |||||
| ret=b->ptr[0]<<(24+b->endbit); | |||||
| if(bits>8){ | |||||
| ret|=b->ptr[1]<<(16+b->endbit); | |||||
| if(bits>16){ | |||||
| ret|=b->ptr[2]<<(8+b->endbit); | |||||
| if(bits>24){ | |||||
| ret|=b->ptr[3]<<(b->endbit); | |||||
| if(bits>32 && b->endbit) | |||||
| ret|=b->ptr[4]>>(8-b->endbit); | |||||
| } | |||||
| } | |||||
| } | |||||
| return ((ret&0xffffffff)>>(m>>1))>>((m+1)>>1); | |||||
| } | |||||
| long oggpack_look1(oggpack_buffer *b){ | |||||
| if(b->endbyte>=b->storage)return(-1); | |||||
| return((b->ptr[0]>>b->endbit)&1); | |||||
| } | |||||
| long oggpackB_look1(oggpack_buffer *b){ | |||||
| if(b->endbyte>=b->storage)return(-1); | |||||
| return((b->ptr[0]>>(7-b->endbit))&1); | |||||
| } | |||||
| void oggpack_adv(oggpack_buffer *b,int bits){ | |||||
| bits+=b->endbit; | |||||
| b->ptr+=bits/8; | |||||
| b->endbyte+=bits/8; | |||||
| b->endbit=bits&7; | |||||
| } | |||||
| void oggpackB_adv(oggpack_buffer *b,int bits){ | |||||
| oggpack_adv(b,bits); | |||||
| } | |||||
| void oggpack_adv1(oggpack_buffer *b){ | |||||
| if(++(b->endbit)>7){ | |||||
| b->endbit=0; | |||||
| b->ptr++; | |||||
| b->endbyte++; | |||||
| } | |||||
| } | |||||
| void oggpackB_adv1(oggpack_buffer *b){ | |||||
| oggpack_adv1(b); | |||||
| } | |||||
| /* bits <= 32 */ | |||||
| long oggpack_read(oggpack_buffer *b,int bits){ | |||||
| long ret; | |||||
| unsigned long m=mask[bits]; | |||||
| bits+=b->endbit; | |||||
| if(b->endbyte+4>=b->storage){ | |||||
| /* not the main path */ | |||||
| ret=-1L; | |||||
| if(b->endbyte*8+bits>b->storage*8)goto overflow; | |||||
| } | |||||
| ret=b->ptr[0]>>b->endbit; | |||||
| if(bits>8){ | |||||
| ret|=b->ptr[1]<<(8-b->endbit); | |||||
| if(bits>16){ | |||||
| ret|=b->ptr[2]<<(16-b->endbit); | |||||
| if(bits>24){ | |||||
| ret|=b->ptr[3]<<(24-b->endbit); | |||||
| if(bits>32 && b->endbit){ | |||||
| ret|=b->ptr[4]<<(32-b->endbit); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| ret&=m; | |||||
| overflow: | |||||
| b->ptr+=bits/8; | |||||
| b->endbyte+=bits/8; | |||||
| b->endbit=bits&7; | |||||
| return(ret); | |||||
| } | |||||
| /* bits <= 32 */ | |||||
| long oggpackB_read(oggpack_buffer *b,int bits){ | |||||
| long ret; | |||||
| long m=32-bits; | |||||
| bits+=b->endbit; | |||||
| if(b->endbyte+4>=b->storage){ | |||||
| /* not the main path */ | |||||
| ret=-1L; | |||||
| if(b->endbyte*8+bits>b->storage*8)goto overflow; | |||||
| } | |||||
| ret=b->ptr[0]<<(24+b->endbit); | |||||
| if(bits>8){ | |||||
| ret|=b->ptr[1]<<(16+b->endbit); | |||||
| if(bits>16){ | |||||
| ret|=b->ptr[2]<<(8+b->endbit); | |||||
| if(bits>24){ | |||||
| ret|=b->ptr[3]<<(b->endbit); | |||||
| if(bits>32 && b->endbit) | |||||
| ret|=b->ptr[4]>>(8-b->endbit); | |||||
| } | |||||
| } | |||||
| } | |||||
| ret=((ret&0xffffffffUL)>>(m>>1))>>((m+1)>>1); | |||||
| overflow: | |||||
| b->ptr+=bits/8; | |||||
| b->endbyte+=bits/8; | |||||
| b->endbit=bits&7; | |||||
| return(ret); | |||||
| } | |||||
| long oggpack_read1(oggpack_buffer *b){ | |||||
| long ret; | |||||
| if(b->endbyte>=b->storage){ | |||||
| /* not the main path */ | |||||
| ret=-1L; | |||||
| goto overflow; | |||||
| } | |||||
| ret=(b->ptr[0]>>b->endbit)&1; | |||||
| overflow: | |||||
| b->endbit++; | |||||
| if(b->endbit>7){ | |||||
| b->endbit=0; | |||||
| b->ptr++; | |||||
| b->endbyte++; | |||||
| } | |||||
| return(ret); | |||||
| } | |||||
| long oggpackB_read1(oggpack_buffer *b){ | |||||
| long ret; | |||||
| if(b->endbyte>=b->storage){ | |||||
| /* not the main path */ | |||||
| ret=-1L; | |||||
| goto overflow; | |||||
| } | |||||
| ret=(b->ptr[0]>>(7-b->endbit))&1; | |||||
| overflow: | |||||
| b->endbit++; | |||||
| if(b->endbit>7){ | |||||
| b->endbit=0; | |||||
| b->ptr++; | |||||
| b->endbyte++; | |||||
| } | |||||
| return(ret); | |||||
| } | |||||
| long oggpack_bytes(oggpack_buffer *b){ | |||||
| return(b->endbyte+(b->endbit+7)/8); | |||||
| } | |||||
| long oggpack_bits(oggpack_buffer *b){ | |||||
| return(b->endbyte*8+b->endbit); | |||||
| } | |||||
| long oggpackB_bytes(oggpack_buffer *b){ | |||||
| return oggpack_bytes(b); | |||||
| } | |||||
| long oggpackB_bits(oggpack_buffer *b){ | |||||
| return oggpack_bits(b); | |||||
| } | |||||
| unsigned char *oggpack_get_buffer(oggpack_buffer *b){ | |||||
| return(b->buffer); | |||||
| } | |||||
| unsigned char *oggpackB_get_buffer(oggpack_buffer *b){ | |||||
| return oggpack_get_buffer(b); | |||||
| } | |||||
| /* Self test of the bitwise routines; everything else is based on | |||||
| them, so they damned well better be solid. */ | |||||
| #ifdef _V_SELFTEST | |||||
| #include <stdio.h> | |||||
| static int ilog(unsigned int v){ | |||||
| int ret=0; | |||||
| while(v){ | |||||
| ret++; | |||||
| v>>=1; | |||||
| } | |||||
| return(ret); | |||||
| } | |||||
| oggpack_buffer o; | |||||
| oggpack_buffer r; | |||||
| void report(char *in){ | |||||
| fprintf(stderr,"%s",in); | |||||
| exit(1); | |||||
| } | |||||
| void cliptest(unsigned long *b,int vals,int bits,int *comp,int compsize){ | |||||
| long bytes,i; | |||||
| unsigned char *buffer; | |||||
| oggpack_reset(&o); | |||||
| for(i=0;i<vals;i++) | |||||
| oggpack_write(&o,b[i],bits?bits:ilog(b[i])); | |||||
| buffer=oggpack_get_buffer(&o); | |||||
| bytes=oggpack_bytes(&o); | |||||
| if(bytes!=compsize)report("wrong number of bytes!\n"); | |||||
| for(i=0;i<bytes;i++)if(buffer[i]!=comp[i]){ | |||||
| for(i=0;i<bytes;i++)fprintf(stderr,"%x %x\n",(int)buffer[i],(int)comp[i]); | |||||
| report("wrote incorrect value!\n"); | |||||
| } | |||||
| oggpack_readinit(&r,buffer,bytes); | |||||
| for(i=0;i<vals;i++){ | |||||
| int tbit=bits?bits:ilog(b[i]); | |||||
| if(oggpack_look(&r,tbit)==-1) | |||||
| report("out of data!\n"); | |||||
| if(oggpack_look(&r,tbit)!=(b[i]&mask[tbit])) | |||||
| report("looked at incorrect value!\n"); | |||||
| if(tbit==1) | |||||
| if(oggpack_look1(&r)!=(b[i]&mask[tbit])) | |||||
| report("looked at single bit incorrect value!\n"); | |||||
| if(tbit==1){ | |||||
| if(oggpack_read1(&r)!=(b[i]&mask[tbit])) | |||||
| report("read incorrect single bit value!\n"); | |||||
| }else{ | |||||
| if(oggpack_read(&r,tbit)!=(b[i]&mask[tbit])) | |||||
| report("read incorrect value!\n"); | |||||
| } | |||||
| } | |||||
| if(oggpack_bytes(&r)!=bytes)report("leftover bytes after read!\n"); | |||||
| } | |||||
| void cliptestB(unsigned long *b,int vals,int bits,int *comp,int compsize){ | |||||
| long bytes,i; | |||||
| unsigned char *buffer; | |||||
| oggpackB_reset(&o); | |||||
| for(i=0;i<vals;i++) | |||||
| oggpackB_write(&o,b[i],bits?bits:ilog(b[i])); | |||||
| buffer=oggpackB_get_buffer(&o); | |||||
| bytes=oggpackB_bytes(&o); | |||||
| if(bytes!=compsize)report("wrong number of bytes!\n"); | |||||
| for(i=0;i<bytes;i++)if(buffer[i]!=comp[i]){ | |||||
| for(i=0;i<bytes;i++)fprintf(stderr,"%x %x\n",(int)buffer[i],(int)comp[i]); | |||||
| report("wrote incorrect value!\n"); | |||||
| } | |||||
| oggpackB_readinit(&r,buffer,bytes); | |||||
| for(i=0;i<vals;i++){ | |||||
| int tbit=bits?bits:ilog(b[i]); | |||||
| if(oggpackB_look(&r,tbit)==-1) | |||||
| report("out of data!\n"); | |||||
| if(oggpackB_look(&r,tbit)!=(b[i]&mask[tbit])) | |||||
| report("looked at incorrect value!\n"); | |||||
| if(tbit==1) | |||||
| if(oggpackB_look1(&r)!=(b[i]&mask[tbit])) | |||||
| report("looked at single bit incorrect value!\n"); | |||||
| if(tbit==1){ | |||||
| if(oggpackB_read1(&r)!=(b[i]&mask[tbit])) | |||||
| report("read incorrect single bit value!\n"); | |||||
| }else{ | |||||
| if(oggpackB_read(&r,tbit)!=(b[i]&mask[tbit])) | |||||
| report("read incorrect value!\n"); | |||||
| } | |||||
| } | |||||
| if(oggpackB_bytes(&r)!=bytes)report("leftover bytes after read!\n"); | |||||
| } | |||||
| int main(void){ | |||||
| unsigned char *buffer; | |||||
| long bytes,i; | |||||
| static unsigned long testbuffer1[]= | |||||
| {18,12,103948,4325,543,76,432,52,3,65,4,56,32,42,34,21,1,23,32,546,456,7, | |||||
| 567,56,8,8,55,3,52,342,341,4,265,7,67,86,2199,21,7,1,5,1,4}; | |||||
| int test1size=43; | |||||
| static unsigned long testbuffer2[]= | |||||
| {216531625L,1237861823,56732452,131,3212421,12325343,34547562,12313212, | |||||
| 1233432,534,5,346435231,14436467,7869299,76326614,167548585, | |||||
| 85525151,0,12321,1,349528352}; | |||||
| int test2size=21; | |||||
| static unsigned long testbuffer3[]= | |||||
| {1,0,14,0,1,0,12,0,1,0,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,1,1,1,1,0,0,1, | |||||
| 0,1,30,1,1,1,0,0,1,0,0,0,12,0,11,0,1,0,0,1}; | |||||
| int test3size=56; | |||||
| static unsigned long large[]= | |||||
| {2136531625L,2137861823,56732452,131,3212421,12325343,34547562,12313212, | |||||
| 1233432,534,5,2146435231,14436467,7869299,76326614,167548585, | |||||
| 85525151,0,12321,1,2146528352}; | |||||
| int onesize=33; | |||||
| static int one[33]={146,25,44,151,195,15,153,176,233,131,196,65,85,172,47,40, | |||||
| 34,242,223,136,35,222,211,86,171,50,225,135,214,75,172, | |||||
| 223,4}; | |||||
| static int oneB[33]={150,101,131,33,203,15,204,216,105,193,156,65,84,85,222, | |||||
| 8,139,145,227,126,34,55,244,171,85,100,39,195,173,18, | |||||
| 245,251,128}; | |||||
| int twosize=6; | |||||
| static int two[6]={61,255,255,251,231,29}; | |||||
| static int twoB[6]={247,63,255,253,249,120}; | |||||
| int threesize=54; | |||||
| static int three[54]={169,2,232,252,91,132,156,36,89,13,123,176,144,32,254, | |||||
| 142,224,85,59,121,144,79,124,23,67,90,90,216,79,23,83, | |||||
| 58,135,196,61,55,129,183,54,101,100,170,37,127,126,10, | |||||
| 100,52,4,14,18,86,77,1}; | |||||
| static int threeB[54]={206,128,42,153,57,8,183,251,13,89,36,30,32,144,183, | |||||
| 130,59,240,121,59,85,223,19,228,180,134,33,107,74,98, | |||||
| 233,253,196,135,63,2,110,114,50,155,90,127,37,170,104, | |||||
| 200,20,254,4,58,106,176,144,0}; | |||||
| int foursize=38; | |||||
| static int four[38]={18,6,163,252,97,194,104,131,32,1,7,82,137,42,129,11,72, | |||||
| 132,60,220,112,8,196,109,64,179,86,9,137,195,208,122,169, | |||||
| 28,2,133,0,1}; | |||||
| static int fourB[38]={36,48,102,83,243,24,52,7,4,35,132,10,145,21,2,93,2,41, | |||||
| 1,219,184,16,33,184,54,149,170,132,18,30,29,98,229,67, | |||||
| 129,10,4,32}; | |||||
| int fivesize=45; | |||||
| static int five[45]={169,2,126,139,144,172,30,4,80,72,240,59,130,218,73,62, | |||||
| 241,24,210,44,4,20,0,248,116,49,135,100,110,130,181,169, | |||||
| 84,75,159,2,1,0,132,192,8,0,0,18,22}; | |||||
| static int fiveB[45]={1,84,145,111,245,100,128,8,56,36,40,71,126,78,213,226, | |||||
| 124,105,12,0,133,128,0,162,233,242,67,152,77,205,77, | |||||
| 172,150,169,129,79,128,0,6,4,32,0,27,9,0}; | |||||
| int sixsize=7; | |||||
| static int six[7]={17,177,170,242,169,19,148}; | |||||
| static int sixB[7]={136,141,85,79,149,200,41}; | |||||
| /* Test read/write together */ | |||||
| /* Later we test against pregenerated bitstreams */ | |||||
| oggpack_writeinit(&o); | |||||
| fprintf(stderr,"\nSmall preclipped packing (LSb): "); | |||||
| cliptest(testbuffer1,test1size,0,one,onesize); | |||||
| fprintf(stderr,"ok."); | |||||
| fprintf(stderr,"\nNull bit call (LSb): "); | |||||
| cliptest(testbuffer3,test3size,0,two,twosize); | |||||
| fprintf(stderr,"ok."); | |||||
| fprintf(stderr,"\nLarge preclipped packing (LSb): "); | |||||
| cliptest(testbuffer2,test2size,0,three,threesize); | |||||
| fprintf(stderr,"ok."); | |||||
| fprintf(stderr,"\n32 bit preclipped packing (LSb): "); | |||||
| oggpack_reset(&o); | |||||
| for(i=0;i<test2size;i++) | |||||
| oggpack_write(&o,large[i],32); | |||||
| buffer=oggpack_get_buffer(&o); | |||||
| bytes=oggpack_bytes(&o); | |||||
| oggpack_readinit(&r,buffer,bytes); | |||||
| for(i=0;i<test2size;i++){ | |||||
| if(oggpack_look(&r,32)==-1)report("out of data. failed!"); | |||||
| if(oggpack_look(&r,32)!=large[i]){ | |||||
| fprintf(stderr,"%ld != %ld (%lx!=%lx):",oggpack_look(&r,32),large[i], | |||||
| oggpack_look(&r,32),large[i]); | |||||
| report("read incorrect value!\n"); | |||||
| } | |||||
| oggpack_adv(&r,32); | |||||
| } | |||||
| if(oggpack_bytes(&r)!=bytes)report("leftover bytes after read!\n"); | |||||
| fprintf(stderr,"ok."); | |||||
| fprintf(stderr,"\nSmall unclipped packing (LSb): "); | |||||
| cliptest(testbuffer1,test1size,7,four,foursize); | |||||
| fprintf(stderr,"ok."); | |||||
| fprintf(stderr,"\nLarge unclipped packing (LSb): "); | |||||
| cliptest(testbuffer2,test2size,17,five,fivesize); | |||||
| fprintf(stderr,"ok."); | |||||
| fprintf(stderr,"\nSingle bit unclipped packing (LSb): "); | |||||
| cliptest(testbuffer3,test3size,1,six,sixsize); | |||||
| fprintf(stderr,"ok."); | |||||
| fprintf(stderr,"\nTesting read past end (LSb): "); | |||||
| oggpack_readinit(&r,"\0\0\0\0\0\0\0\0",8); | |||||
| for(i=0;i<64;i++){ | |||||
| if(oggpack_read(&r,1)!=0){ | |||||
| fprintf(stderr,"failed; got -1 prematurely.\n"); | |||||
| exit(1); | |||||
| } | |||||
| } | |||||
| if(oggpack_look(&r,1)!=-1 || | |||||
| oggpack_read(&r,1)!=-1){ | |||||
| fprintf(stderr,"failed; read past end without -1.\n"); | |||||
| exit(1); | |||||
| } | |||||
| oggpack_readinit(&r,"\0\0\0\0\0\0\0\0",8); | |||||
| if(oggpack_read(&r,30)!=0 || oggpack_read(&r,16)!=0){ | |||||
| fprintf(stderr,"failed 2; got -1 prematurely.\n"); | |||||
| exit(1); | |||||
| } | |||||
| if(oggpack_look(&r,18)!=0 || | |||||
| oggpack_look(&r,18)!=0){ | |||||
| fprintf(stderr,"failed 3; got -1 prematurely.\n"); | |||||
| exit(1); | |||||
| } | |||||
| if(oggpack_look(&r,19)!=-1 || | |||||
| oggpack_look(&r,19)!=-1){ | |||||
| fprintf(stderr,"failed; read past end without -1.\n"); | |||||
| exit(1); | |||||
| } | |||||
| if(oggpack_look(&r,32)!=-1 || | |||||
| oggpack_look(&r,32)!=-1){ | |||||
| fprintf(stderr,"failed; read past end without -1.\n"); | |||||
| exit(1); | |||||
| } | |||||
| oggpack_writeclear(&o); | |||||
| fprintf(stderr,"ok.\n"); | |||||
| /********** lazy, cut-n-paste retest with MSb packing ***********/ | |||||
| /* Test read/write together */ | |||||
| /* Later we test against pregenerated bitstreams */ | |||||
| oggpackB_writeinit(&o); | |||||
| fprintf(stderr,"\nSmall preclipped packing (MSb): "); | |||||
| cliptestB(testbuffer1,test1size,0,oneB,onesize); | |||||
| fprintf(stderr,"ok."); | |||||
| fprintf(stderr,"\nNull bit call (MSb): "); | |||||
| cliptestB(testbuffer3,test3size,0,twoB,twosize); | |||||
| fprintf(stderr,"ok."); | |||||
| fprintf(stderr,"\nLarge preclipped packing (MSb): "); | |||||
| cliptestB(testbuffer2,test2size,0,threeB,threesize); | |||||
| fprintf(stderr,"ok."); | |||||
| fprintf(stderr,"\n32 bit preclipped packing (MSb): "); | |||||
| oggpackB_reset(&o); | |||||
| for(i=0;i<test2size;i++) | |||||
| oggpackB_write(&o,large[i],32); | |||||
| buffer=oggpackB_get_buffer(&o); | |||||
| bytes=oggpackB_bytes(&o); | |||||
| oggpackB_readinit(&r,buffer,bytes); | |||||
| for(i=0;i<test2size;i++){ | |||||
| if(oggpackB_look(&r,32)==-1)report("out of data. failed!"); | |||||
| if(oggpackB_look(&r,32)!=large[i]){ | |||||
| fprintf(stderr,"%ld != %ld (%lx!=%lx):",oggpackB_look(&r,32),large[i], | |||||
| oggpackB_look(&r,32),large[i]); | |||||
| report("read incorrect value!\n"); | |||||
| } | |||||
| oggpackB_adv(&r,32); | |||||
| } | |||||
| if(oggpackB_bytes(&r)!=bytes)report("leftover bytes after read!\n"); | |||||
| fprintf(stderr,"ok."); | |||||
| fprintf(stderr,"\nSmall unclipped packing (MSb): "); | |||||
| cliptestB(testbuffer1,test1size,7,fourB,foursize); | |||||
| fprintf(stderr,"ok."); | |||||
| fprintf(stderr,"\nLarge unclipped packing (MSb): "); | |||||
| cliptestB(testbuffer2,test2size,17,fiveB,fivesize); | |||||
| fprintf(stderr,"ok."); | |||||
| fprintf(stderr,"\nSingle bit unclipped packing (MSb): "); | |||||
| cliptestB(testbuffer3,test3size,1,sixB,sixsize); | |||||
| fprintf(stderr,"ok."); | |||||
| fprintf(stderr,"\nTesting read past end (MSb): "); | |||||
| oggpackB_readinit(&r,"\0\0\0\0\0\0\0\0",8); | |||||
| for(i=0;i<64;i++){ | |||||
| if(oggpackB_read(&r,1)!=0){ | |||||
| fprintf(stderr,"failed; got -1 prematurely.\n"); | |||||
| exit(1); | |||||
| } | |||||
| } | |||||
| if(oggpackB_look(&r,1)!=-1 || | |||||
| oggpackB_read(&r,1)!=-1){ | |||||
| fprintf(stderr,"failed; read past end without -1.\n"); | |||||
| exit(1); | |||||
| } | |||||
| oggpackB_readinit(&r,"\0\0\0\0\0\0\0\0",8); | |||||
| if(oggpackB_read(&r,30)!=0 || oggpackB_read(&r,16)!=0){ | |||||
| fprintf(stderr,"failed 2; got -1 prematurely.\n"); | |||||
| exit(1); | |||||
| } | |||||
| if(oggpackB_look(&r,18)!=0 || | |||||
| oggpackB_look(&r,18)!=0){ | |||||
| fprintf(stderr,"failed 3; got -1 prematurely.\n"); | |||||
| exit(1); | |||||
| } | |||||
| if(oggpackB_look(&r,19)!=-1 || | |||||
| oggpackB_look(&r,19)!=-1){ | |||||
| fprintf(stderr,"failed; read past end without -1.\n"); | |||||
| exit(1); | |||||
| } | |||||
| if(oggpackB_look(&r,32)!=-1 || | |||||
| oggpackB_look(&r,32)!=-1){ | |||||
| fprintf(stderr,"failed; read past end without -1.\n"); | |||||
| exit(1); | |||||
| } | |||||
| oggpackB_writeclear(&o); | |||||
| fprintf(stderr,"ok.\n\n"); | |||||
| return(0); | |||||
| } | |||||
| #endif /* _V_SELFTEST */ | |||||
| #undef BUFFER_INCREMENT | |||||
| #endif | |||||
| @@ -0,0 +1,239 @@ | |||||
| /******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * | |||||
| * by the XIPHOPHORUS Company http://www.xiph.org/ * | |||||
| ******************************************************************** | |||||
| function: libvorbis codec headers | |||||
| last mod: $Id: codec.h,v 1.1 2007/06/07 17:48:18 jules_rms Exp $ | |||||
| ********************************************************************/ | |||||
| #ifndef _vorbis_codec_h_ | |||||
| #define _vorbis_codec_h_ | |||||
| #ifdef __cplusplus | |||||
| extern "C" | |||||
| { | |||||
| #endif /* __cplusplus */ | |||||
| #include "ogg.h" | |||||
| typedef struct vorbis_info{ | |||||
| int version; | |||||
| int channels; | |||||
| long rate; | |||||
| /* The below bitrate declarations are *hints*. | |||||
| Combinations of the three values carry the following implications: | |||||
| all three set to the same value: | |||||
| implies a fixed rate bitstream | |||||
| only nominal set: | |||||
| implies a VBR stream that averages the nominal bitrate. No hard | |||||
| upper/lower limit | |||||
| upper and or lower set: | |||||
| implies a VBR bitstream that obeys the bitrate limits. nominal | |||||
| may also be set to give a nominal rate. | |||||
| none set: | |||||
| the coder does not care to speculate. | |||||
| */ | |||||
| long bitrate_upper; | |||||
| long bitrate_nominal; | |||||
| long bitrate_lower; | |||||
| long bitrate_window; | |||||
| void *codec_setup; | |||||
| } vorbis_info; | |||||
| /* vorbis_dsp_state buffers the current vorbis audio | |||||
| analysis/synthesis state. The DSP state belongs to a specific | |||||
| logical bitstream ****************************************************/ | |||||
| typedef struct vorbis_dsp_state{ | |||||
| int analysisp; | |||||
| vorbis_info *vi; | |||||
| float **pcm; | |||||
| float **pcmret; | |||||
| int pcm_storage; | |||||
| int pcm_current; | |||||
| int pcm_returned; | |||||
| int preextrapolate; | |||||
| int eofflag; | |||||
| long lW; | |||||
| long W; | |||||
| long nW; | |||||
| long centerW; | |||||
| ogg_int64_t granulepos; | |||||
| ogg_int64_t sequence; | |||||
| ogg_int64_t glue_bits; | |||||
| ogg_int64_t time_bits; | |||||
| ogg_int64_t floor_bits; | |||||
| ogg_int64_t res_bits; | |||||
| void *backend_state; | |||||
| } vorbis_dsp_state; | |||||
| typedef struct vorbis_block{ | |||||
| /* necessary stream state for linking to the framing abstraction */ | |||||
| float **pcm; /* this is a pointer into local storage */ | |||||
| oggpack_buffer opb; | |||||
| long lW; | |||||
| long W; | |||||
| long nW; | |||||
| int pcmend; | |||||
| int mode; | |||||
| int eofflag; | |||||
| ogg_int64_t granulepos; | |||||
| ogg_int64_t sequence; | |||||
| vorbis_dsp_state *vd; /* For read-only access of configuration */ | |||||
| /* local storage to avoid remallocing; it's up to the mapping to | |||||
| structure it */ | |||||
| void *localstore; | |||||
| long localtop; | |||||
| long localalloc; | |||||
| long totaluse; | |||||
| struct alloc_chain *reap; | |||||
| /* bitmetrics for the frame */ | |||||
| long glue_bits; | |||||
| long time_bits; | |||||
| long floor_bits; | |||||
| long res_bits; | |||||
| void *internal; | |||||
| } vorbis_block; | |||||
| /* vorbis_block is a single block of data to be processed as part of | |||||
| the analysis/synthesis stream; it belongs to a specific logical | |||||
| bitstream, but is independant from other vorbis_blocks belonging to | |||||
| that logical bitstream. *************************************************/ | |||||
| struct alloc_chain{ | |||||
| void *ptr; | |||||
| struct alloc_chain *next; | |||||
| }; | |||||
| /* vorbis_info contains all the setup information specific to the | |||||
| specific compression/decompression mode in progress (eg, | |||||
| psychoacoustic settings, channel setup, options, codebook | |||||
| etc). vorbis_info and substructures are in backends.h. | |||||
| *********************************************************************/ | |||||
| /* the comments are not part of vorbis_info so that vorbis_info can be | |||||
| static storage */ | |||||
| typedef struct vorbis_comment{ | |||||
| /* unlimited user comment fields. libvorbis writes 'libvorbis' | |||||
| whatever vendor is set to in encode */ | |||||
| char **user_comments; | |||||
| int *comment_lengths; | |||||
| int comments; | |||||
| char *vendor; | |||||
| } vorbis_comment; | |||||
| /* libvorbis encodes in two abstraction layers; first we perform DSP | |||||
| and produce a packet (see docs/analysis.txt). The packet is then | |||||
| coded into a framed OggSquish bitstream by the second layer (see | |||||
| docs/framing.txt). Decode is the reverse process; we sync/frame | |||||
| the bitstream and extract individual packets, then decode the | |||||
| packet back into PCM audio. | |||||
| The extra framing/packetizing is used in streaming formats, such as | |||||
| files. Over the net (such as with UDP), the framing and | |||||
| packetization aren't necessary as they're provided by the transport | |||||
| and the streaming layer is not used */ | |||||
| /* Vorbis PRIMITIVES: general ***************************************/ | |||||
| extern void vorbis_info_init(vorbis_info *vi); | |||||
| extern void vorbis_info_clear(vorbis_info *vi); | |||||
| extern int vorbis_info_blocksize(vorbis_info *vi,int zo); | |||||
| extern void vorbis_comment_init(vorbis_comment *vc); | |||||
| extern void vorbis_comment_add(vorbis_comment *vc, char *comment); | |||||
| extern void vorbis_comment_add_tag(vorbis_comment *vc, | |||||
| const char *tag, char *contents); | |||||
| extern char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count); | |||||
| extern int vorbis_comment_query_count(vorbis_comment *vc, char *tag); | |||||
| extern void vorbis_comment_clear(vorbis_comment *vc); | |||||
| extern int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb); | |||||
| extern int vorbis_block_clear(vorbis_block *vb); | |||||
| extern void vorbis_dsp_clear(vorbis_dsp_state *v); | |||||
| extern double vorbis_granule_time(vorbis_dsp_state *v, | |||||
| ogg_int64_t granulepos); | |||||
| /* Vorbis PRIMITIVES: analysis/DSP layer ****************************/ | |||||
| extern int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi); | |||||
| extern int vorbis_commentheader_out(vorbis_comment *vc, ogg_packet *op); | |||||
| extern int vorbis_analysis_headerout(vorbis_dsp_state *v, | |||||
| vorbis_comment *vc, | |||||
| ogg_packet *op, | |||||
| ogg_packet *op_comm, | |||||
| ogg_packet *op_code); | |||||
| extern float **vorbis_analysis_buffer(vorbis_dsp_state *v,int vals); | |||||
| extern int vorbis_analysis_wrote(vorbis_dsp_state *v,int vals); | |||||
| extern int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb); | |||||
| extern int vorbis_analysis(vorbis_block *vb,ogg_packet *op); | |||||
| extern int vorbis_bitrate_addblock(vorbis_block *vb); | |||||
| extern int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd, | |||||
| ogg_packet *op); | |||||
| /* Vorbis PRIMITIVES: synthesis layer *******************************/ | |||||
| extern int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc, | |||||
| ogg_packet *op); | |||||
| extern int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi); | |||||
| extern int vorbis_synthesis_restart(vorbis_dsp_state *v); | |||||
| extern int vorbis_synthesis(vorbis_block *vb,ogg_packet *op); | |||||
| extern int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op); | |||||
| extern int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb); | |||||
| extern int vorbis_synthesis_pcmout(vorbis_dsp_state *v,float ***pcm); | |||||
| extern int vorbis_synthesis_lapout(vorbis_dsp_state *v,float ***pcm); | |||||
| extern int vorbis_synthesis_read(vorbis_dsp_state *v,int samples); | |||||
| extern long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op); | |||||
| extern int vorbis_synthesis_halfrate(vorbis_info *v,int flag); | |||||
| extern int vorbis_synthesis_halfrate_p(vorbis_info *v); | |||||
| /* Vorbis ERRORS and return codes ***********************************/ | |||||
| #define OV_FALSE -1 | |||||
| #define OV_EOF -2 | |||||
| #define OV_HOLE -3 | |||||
| #define OV_EREAD -128 | |||||
| #define OV_EFAULT -129 | |||||
| #define OV_EIMPL -130 | |||||
| #define OV_EINVAL -131 | |||||
| #define OV_ENOTVORBIS -132 | |||||
| #define OV_EBADHEADER -133 | |||||
| #define OV_EVERSION -134 | |||||
| #define OV_ENOTAUDIO -135 | |||||
| #define OV_EBADPACKET -136 | |||||
| #define OV_EBADLINK -137 | |||||
| #define OV_ENOSEEK -138 | |||||
| #ifdef __cplusplus | |||||
| } | |||||
| #endif /* __cplusplus */ | |||||
| #endif | |||||
| @@ -0,0 +1,10 @@ | |||||
| #ifndef __CONFIG_TYPES_H__ | |||||
| #define __CONFIG_TYPES_H__ | |||||
| typedef int16_t ogg_int16_t; | |||||
| typedef unsigned short ogg_uint16_t; | |||||
| typedef int32_t ogg_int32_t; | |||||
| typedef unsigned int ogg_uint32_t; | |||||
| typedef int64_t ogg_int64_t; | |||||
| #endif | |||||
| @@ -0,0 +1,34 @@ | |||||
| /* | |||||
| ============================================================================== | |||||
| This file is part of the JUCE library - "Jules' Utility Class Extensions" | |||||
| Copyright 2004-9 by Raw Material Software Ltd. | |||||
| ------------------------------------------------------------------------------ | |||||
| JUCE can be redistributed and/or modified under the terms of the GNU General | |||||
| Public License (Version 2), as published by the Free Software Foundation. | |||||
| A copy of the license is included in the JUCE distribution, or can be found | |||||
| online at www.gnu.org/licenses. | |||||
| JUCE is distributed in the hope that it will be useful, but WITHOUT ANY | |||||
| WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR | |||||
| A PARTICULAR PURPOSE. See the GNU General Public License for more details. | |||||
| ------------------------------------------------------------------------------ | |||||
| To release a closed-source product which uses JUCE, commercial licenses are | |||||
| available: visit www.rawmaterialsoftware.com/juce for more information. | |||||
| ============================================================================== | |||||
| */ | |||||
| // This file is included at the start of each Ogg-Vorbis .c file, just to do a few housekeeping | |||||
| // tasks.. | |||||
| #include "../../../../juce_Config.h" | |||||
| #ifdef _MSC_VER | |||||
| #pragma warning (disable: 4267 4127 4244 4996 4100 4701 4702 4013 4133 4206 4305 4189 4706) | |||||
| #endif | |||||
| @@ -0,0 +1,3 @@ | |||||
| Monty <monty@xiph.org> | |||||
| and the rest of the Xiph.org Foundation. | |||||
| @@ -0,0 +1,28 @@ | |||||
| Copyright (c) 2002-2004 Xiph.org Foundation | |||||
| 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 Xiph.org Foundation 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 FOUNDATION | |||||
| 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. | |||||
| @@ -0,0 +1,132 @@ | |||||
| ******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2004 * | |||||
| * by the Xiph.org Foundation, http://www.xiph.org/ * | |||||
| * * | |||||
| ******************************************************************** | |||||
| Vorbis is a general purpose audio and music encoding format | |||||
| contemporary to MPEG-4's AAC and TwinVQ, the next generation beyond | |||||
| MPEG audio layer 3. Unlike the MPEG sponsored formats (and other | |||||
| proprietary formats such as RealAudio G2 and Windows' flavor of the | |||||
| month), the Vorbis CODEC specification belongs to the public domain. | |||||
| All the technical details are published and documented, and any | |||||
| software entity may make full use of the format without license | |||||
| fee, royalty or patent concerns. | |||||
| This package contains: | |||||
| * libvorbis, a BSD-style license software implementation of | |||||
| the Vorbis specification by the Xiph.Org Foundation | |||||
| (http://www.xiph.org/) | |||||
| * libvorbisfile, a BSD-style license convenience library | |||||
| built on Vorbis designed to simplify common uses | |||||
| * libvorbisenc, a BSD-style license library that provides a simple, | |||||
| programmatic encoding setup interface | |||||
| * example code making use of libogg, libvorbis, libvorbisfile and | |||||
| libvorbisenc | |||||
| WHAT'S HERE: | |||||
| This source distribution includes libvorbis and an example | |||||
| encoder/player to demonstrate use of libvorbis as well as | |||||
| documentation on the Ogg Vorbis audio coding format. | |||||
| You'll need libogg (distributed separately) to compile this library. | |||||
| A more comprehensive set of utilities is available in the vorbis-tools | |||||
| package. | |||||
| Directory: | |||||
| ./lib The source for the libraries, a BSD-license implementation | |||||
| of the public domain Ogg Vorbis audio encoding format. | |||||
| ./include Library API headers | |||||
| ./debian Rules/spec files for building Debian .deb packages | |||||
| ./doc Vorbis documentation | |||||
| ./examples Example code illustrating programmatic use of libvorbis, | |||||
| libvorbisfile and libvorbisenc | |||||
| ./mac Codewarrior project files and build tweaks for MacOS. | |||||
| ./macosx Project files for MacOS X. | |||||
| ./win32 Win32 projects files and build automation | |||||
| ./vq Internal utilities for training/building new LSP/residue | |||||
| and auxiliary codebooks. | |||||
| CONTACT: | |||||
| The Ogg homepage is located at 'http://www.xiph.org/ogg/'. | |||||
| Vorbis's homepage is located at 'http://www.xiph.org/vorbis/'. | |||||
| Up to date technical documents, contact information, source code and | |||||
| pre-built utilities may be found there. | |||||
| The user website for Ogg Vorbis software and audio is http://vorbis.com/ | |||||
| BUILDING FROM TRUNK: | |||||
| Development source is under subversion revision control at | |||||
| http://svn.xiph.org/trunk/vorbis/. You will also need the | |||||
| newest versions of autoconf, automake, and libtool in order | |||||
| to compile vorbis from development source. A configure script | |||||
| is provided for you in the source tarball distributions. | |||||
| [update or checkout latest source] | |||||
| ./autogen.sh | |||||
| make | |||||
| and as root if desired: | |||||
| make install | |||||
| This will install the vorbis libraries (static and shared) into | |||||
| /usr/local/lib, includes into /usr/local/include and API manpages | |||||
| (once we write some) into /usr/local/man. | |||||
| BUILDING FROM TARBALL DISTRIBUTIONS: | |||||
| ./configure | |||||
| make | |||||
| and optionally (as root): | |||||
| make install | |||||
| BUILDING RPMS: | |||||
| after normal configuring: | |||||
| make dist | |||||
| rpm -ta libvorbis-<version>.tar.gz | |||||
| BUILDING ON MACOS 9: | |||||
| Vorbis on MacOS 9 is built using Metroworks CodeWarrior. To build it, | |||||
| first verify that the Ogg libraries are already built following the | |||||
| instructions in the Ogg module README. Open vorbis/mac/libvorbis.mcp, | |||||
| switch to the "Targets" pane, select everything, and make the project. | |||||
| Do the same thing to build libvorbisenc.mcp, and libvorbisfile.mcp (in | |||||
| that order). In vorbis/mac/Output you will now have both debug and final | |||||
| versions of Vorbis shared libraries to link your projects against. | |||||
| To build a project using Ogg Vorbis, add access paths to your | |||||
| CodeWarrior project for the ogg/include, ogg/mac/Output, | |||||
| vorbis/include, and vorbis/mac/Output folders. Be sure that | |||||
| "interpret DOS and Unix paths" is turned on in your project; it can | |||||
| be found in the "access paths" pane in your project settings. Now | |||||
| simply add the shared libraries you need to your project (OggLib and | |||||
| VorbisLib at least) and #include "ogg/ogg.h" and "vorbis/codec.h" | |||||
| wherever you need to access Ogg and Vorbis functionality. | |||||
| @@ -0,0 +1,113 @@ | |||||
| /******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * | |||||
| * by the XIPHOPHORUS Company http://www.xiph.org/ * | |||||
| * * | |||||
| ******************************************************************** | |||||
| function: single-block PCM analysis mode dispatch | |||||
| last mod: $Id: analysis.c,v 1.1 2007/06/07 17:49:17 jules_rms Exp $ | |||||
| ********************************************************************/ | |||||
| #include "../../juce_OggVorbisHeader.h" | |||||
| #if JUCE_USE_OGGVORBIS | |||||
| #include <stdio.h> | |||||
| #include <string.h> | |||||
| #include <math.h> | |||||
| #include "../../ogg.h" | |||||
| #include "../../codec.h" | |||||
| #include "codec_internal.h" | |||||
| #include "registry.h" | |||||
| #include "scales.h" | |||||
| #include "os.h" | |||||
| #include "misc.h" | |||||
| int analysis_noisy=1; | |||||
| /* decides between modes, dispatches to the appropriate mapping. */ | |||||
| int vorbis_analysis(vorbis_block *vb, ogg_packet *op){ | |||||
| int ret,i; | |||||
| vorbis_block_internal *vbi=(vorbis_block_internal *)vb->internal; | |||||
| vb->glue_bits=0; | |||||
| vb->time_bits=0; | |||||
| vb->floor_bits=0; | |||||
| vb->res_bits=0; | |||||
| /* first things first. Make sure encode is ready */ | |||||
| for(i=0;i<PACKETBLOBS;i++) | |||||
| oggpack_reset(vbi->packetblob[i]); | |||||
| /* we only have one mapping type (0), and we let the mapping code | |||||
| itself figure out what soft mode to use. This allows easier | |||||
| bitrate management */ | |||||
| if((ret=_mapping_P[0]->forward(vb))) | |||||
| return(ret); | |||||
| if(op){ | |||||
| if(vorbis_bitrate_managed(vb)) | |||||
| /* The app is using a bitmanaged mode... but not using the | |||||
| bitrate management interface. */ | |||||
| return(OV_EINVAL); | |||||
| op->packet=oggpack_get_buffer(&vb->opb); | |||||
| op->bytes=oggpack_bytes(&vb->opb); | |||||
| op->b_o_s=0; | |||||
| op->e_o_s=vb->eofflag; | |||||
| op->granulepos=vb->granulepos; | |||||
| op->packetno=vb->sequence; /* for sake of completeness */ | |||||
| } | |||||
| return(0); | |||||
| } | |||||
| /* there was no great place to put this.... */ | |||||
| void _analysis_output_always(const char *base,int i,float *v,int n,int bark,int dB,ogg_int64_t off){ | |||||
| int j; | |||||
| FILE *of; | |||||
| char buffer[80]; | |||||
| /* if(i==5870){*/ | |||||
| sprintf(buffer,"%s_%d.m",base,i); | |||||
| of=fopen(buffer,"w"); | |||||
| if(!of)perror("failed to open data dump file"); | |||||
| for(j=0;j<n;j++){ | |||||
| if(bark){ | |||||
| float b=toBARK((4000.f*j/n)+.25); | |||||
| fprintf(of,"%f ",b); | |||||
| }else | |||||
| if(off!=0) | |||||
| fprintf(of,"%f ",(double)(j+off)/8000.); | |||||
| else | |||||
| fprintf(of,"%f ",(double)j); | |||||
| if(dB){ | |||||
| float val; | |||||
| if(v[j]==0.) | |||||
| val=-140.; | |||||
| else | |||||
| val=todB(v+j); | |||||
| fprintf(of,"%f\n",val); | |||||
| }else{ | |||||
| fprintf(of,"%f\n",v[j]); | |||||
| } | |||||
| } | |||||
| fclose(of); | |||||
| /* } */ | |||||
| } | |||||
| void _analysis_output(char *base,int i,float *v,int n,int bark,int dB, | |||||
| ogg_int64_t off){ | |||||
| if(analysis_noisy)_analysis_output_always(base,i,v,n,bark,dB,off); | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,144 @@ | |||||
| /******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * | |||||
| * by the XIPHOPHORUS Company http://www.xiph.org/ * | |||||
| * * | |||||
| ******************************************************************** | |||||
| function: libvorbis backend and mapping structures; needed for | |||||
| static mode headers | |||||
| last mod: $Id: backends.h,v 1.1 2007/06/07 17:49:17 jules_rms Exp $ | |||||
| ********************************************************************/ | |||||
| /* this is exposed up here because we need it for static modes. | |||||
| Lookups for each backend aren't exposed because there's no reason | |||||
| to do so */ | |||||
| #ifndef _vorbis_backend_h_ | |||||
| #define _vorbis_backend_h_ | |||||
| #include "codec_internal.h" | |||||
| /* this would all be simpler/shorter with templates, but.... */ | |||||
| /* Floor backend generic *****************************************/ | |||||
| typedef struct{ | |||||
| void (*pack) (vorbis_info_floor *,oggpack_buffer *); | |||||
| vorbis_info_floor *(*unpack)(vorbis_info *,oggpack_buffer *); | |||||
| vorbis_look_floor *(*look) (vorbis_dsp_state *,vorbis_info_floor *); | |||||
| void (*free_info) (vorbis_info_floor *); | |||||
| void (*free_look) (vorbis_look_floor *); | |||||
| void *(*inverse1) (struct vorbis_block *,vorbis_look_floor *); | |||||
| int (*inverse2) (struct vorbis_block *,vorbis_look_floor *, | |||||
| void *buffer,float *); | |||||
| } vorbis_func_floor; | |||||
| typedef struct{ | |||||
| int order; | |||||
| long rate; | |||||
| long barkmap; | |||||
| int ampbits; | |||||
| int ampdB; | |||||
| int numbooks; /* <= 16 */ | |||||
| int books[16]; | |||||
| float lessthan; /* encode-only config setting hacks for libvorbis */ | |||||
| float greaterthan; /* encode-only config setting hacks for libvorbis */ | |||||
| } vorbis_info_floor0; | |||||
| #define VIF_POSIT 63 | |||||
| #define VIF_CLASS 16 | |||||
| #define VIF_PARTS 31 | |||||
| typedef struct{ | |||||
| int partitions; /* 0 to 31 */ | |||||
| int partitionclass[VIF_PARTS]; /* 0 to 15 */ | |||||
| int class_dim[VIF_CLASS]; /* 1 to 8 */ | |||||
| int class_subs[VIF_CLASS]; /* 0,1,2,3 (bits: 1<<n poss) */ | |||||
| int class_book[VIF_CLASS]; /* subs ^ dim entries */ | |||||
| int class_subbook[VIF_CLASS][8]; /* [VIF_CLASS][subs] */ | |||||
| int mult; /* 1 2 3 or 4 */ | |||||
| int postlist[VIF_POSIT+2]; /* first two implicit */ | |||||
| /* encode side analysis parameters */ | |||||
| float maxover; | |||||
| float maxunder; | |||||
| float maxerr; | |||||
| float twofitweight; | |||||
| float twofitatten; | |||||
| int n; | |||||
| } vorbis_info_floor1; | |||||
| /* Residue backend generic *****************************************/ | |||||
| typedef struct{ | |||||
| void (*pack) (vorbis_info_residue *,oggpack_buffer *); | |||||
| vorbis_info_residue *(*unpack)(vorbis_info *,oggpack_buffer *); | |||||
| vorbis_look_residue *(*look) (vorbis_dsp_state *, | |||||
| vorbis_info_residue *); | |||||
| void (*free_info) (vorbis_info_residue *); | |||||
| void (*free_look) (vorbis_look_residue *); | |||||
| long **(*classx) (struct vorbis_block *,vorbis_look_residue *, | |||||
| float **,int *,int); | |||||
| int (*forward) (oggpack_buffer *,struct vorbis_block *, | |||||
| vorbis_look_residue *, | |||||
| float **,float **,int *,int,long **); | |||||
| int (*inverse) (struct vorbis_block *,vorbis_look_residue *, | |||||
| float **,int *,int); | |||||
| } vorbis_func_residue; | |||||
| typedef struct vorbis_info_residue0{ | |||||
| /* block-partitioned VQ coded straight residue */ | |||||
| long begin; | |||||
| long end; | |||||
| /* first stage (lossless partitioning) */ | |||||
| int grouping; /* group n vectors per partition */ | |||||
| int partitions; /* possible codebooks for a partition */ | |||||
| int groupbook; /* huffbook for partitioning */ | |||||
| int secondstages[64]; /* expanded out to pointers in lookup */ | |||||
| int booklist[256]; /* list of second stage books */ | |||||
| float classmetric1[64]; | |||||
| float classmetric2[64]; | |||||
| } vorbis_info_residue0; | |||||
| /* Mapping backend generic *****************************************/ | |||||
| typedef struct{ | |||||
| void (*pack) (vorbis_info *,vorbis_info_mapping *, | |||||
| oggpack_buffer *); | |||||
| vorbis_info_mapping *(*unpack)(vorbis_info *,oggpack_buffer *); | |||||
| void (*free_info) (vorbis_info_mapping *); | |||||
| int (*forward) (struct vorbis_block *vb); | |||||
| int (*inverse) (struct vorbis_block *vb,vorbis_info_mapping *); | |||||
| } vorbis_func_mapping; | |||||
| typedef struct vorbis_info_mapping0{ | |||||
| int submaps; /* <= 16 */ | |||||
| int chmuxlist[256]; /* up to 256 channels in a Vorbis stream */ | |||||
| int floorsubmap[16]; /* [mux] submap to floors */ | |||||
| int residuesubmap[16]; /* [mux] submap to residue */ | |||||
| int coupling_steps; | |||||
| int coupling_mag[256]; | |||||
| int coupling_ang[256]; | |||||
| } vorbis_info_mapping0; | |||||
| #endif | |||||
| @@ -0,0 +1,259 @@ | |||||
| /******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * | |||||
| * by the XIPHOPHORUS Company http://www.xiph.org/ * | |||||
| * * | |||||
| ******************************************************************** | |||||
| function: bitrate tracking and management | |||||
| last mod: $Id: bitrate.c,v 1.1 2007/06/07 17:49:17 jules_rms Exp $ | |||||
| ********************************************************************/ | |||||
| #include "../../juce_OggVorbisHeader.h" | |||||
| #if JUCE_USE_OGGVORBIS | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| #include <math.h> | |||||
| #include "../../ogg.h" | |||||
| #include "../../codec.h" | |||||
| #include "codec_internal.h" | |||||
| #include "os.h" | |||||
| #include "misc.h" | |||||
| #include "bitrate.h" | |||||
| /* compute bitrate tracking setup */ | |||||
| void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bm){ | |||||
| codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; | |||||
| bitrate_manager_info *bi=&ci->bi; | |||||
| memset(bm,0,sizeof(*bm)); | |||||
| if(bi && (bi->reservoir_bits>0)){ | |||||
| long ratesamples=vi->rate; | |||||
| int halfsamples=ci->blocksizes[0]>>1; | |||||
| bm->short_per_long=ci->blocksizes[1]/ci->blocksizes[0]; | |||||
| bm->managed=1; | |||||
| bm->avg_bitsper= rint(1.*bi->avg_rate*halfsamples/ratesamples); | |||||
| bm->min_bitsper= rint(1.*bi->min_rate*halfsamples/ratesamples); | |||||
| bm->max_bitsper= rint(1.*bi->max_rate*halfsamples/ratesamples); | |||||
| bm->avgfloat=PACKETBLOBS/2; | |||||
| /* not a necessary fix, but one that leads to a more balanced | |||||
| typical initialization */ | |||||
| { | |||||
| long desired_fill=bi->reservoir_bits*bi->reservoir_bias; | |||||
| bm->minmax_reservoir=desired_fill; | |||||
| bm->avg_reservoir=desired_fill; | |||||
| } | |||||
| } | |||||
| } | |||||
| void vorbis_bitrate_clear(bitrate_manager_state *bm){ | |||||
| memset(bm,0,sizeof(*bm)); | |||||
| return; | |||||
| } | |||||
| int vorbis_bitrate_managed(vorbis_block *vb){ | |||||
| vorbis_dsp_state *vd=vb->vd; | |||||
| private_state *b=(private_state*)vd->backend_state; | |||||
| bitrate_manager_state *bm=&b->bms; | |||||
| if(bm && bm->managed)return(1); | |||||
| return(0); | |||||
| } | |||||
| /* finish taking in the block we just processed */ | |||||
| int vorbis_bitrate_addblock(vorbis_block *vb){ | |||||
| vorbis_block_internal *vbi=(vorbis_block_internal*)vb->internal; | |||||
| vorbis_dsp_state *vd=vb->vd; | |||||
| private_state *b=(private_state*)vd->backend_state; | |||||
| bitrate_manager_state *bm=&b->bms; | |||||
| vorbis_info *vi=vd->vi; | |||||
| codec_setup_info *ci=(codec_setup_info*)vi->codec_setup; | |||||
| bitrate_manager_info *bi=&ci->bi; | |||||
| int choice=rint(bm->avgfloat); | |||||
| long this_bits=oggpack_bytes(vbi->packetblob[choice])*8; | |||||
| long min_target_bits=(vb->W?bm->min_bitsper*bm->short_per_long:bm->min_bitsper); | |||||
| long max_target_bits=(vb->W?bm->max_bitsper*bm->short_per_long:bm->max_bitsper); | |||||
| int samples=ci->blocksizes[vb->W]>>1; | |||||
| long desired_fill=bi->reservoir_bits*bi->reservoir_bias; | |||||
| if(!bm->managed){ | |||||
| /* not a bitrate managed stream, but for API simplicity, we'll | |||||
| buffer the packet to keep the code path clean */ | |||||
| if(bm->vb)return(-1); /* one has been submitted without | |||||
| being claimed */ | |||||
| bm->vb=vb; | |||||
| return(0); | |||||
| } | |||||
| bm->vb=vb; | |||||
| /* look ahead for avg floater */ | |||||
| if(bm->avg_bitsper>0){ | |||||
| double slew=0.; | |||||
| long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper); | |||||
| double slewlimit= 15./bi->slew_damp; | |||||
| /* choosing a new floater: | |||||
| if we're over target, we slew down | |||||
| if we're under target, we slew up | |||||
| choose slew as follows: look through packetblobs of this frame | |||||
| and set slew as the first in the appropriate direction that | |||||
| gives us the slew we want. This may mean no slew if delta is | |||||
| already favorable. | |||||
| Then limit slew to slew max */ | |||||
| if(bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){ | |||||
| while(choice>0 && this_bits>avg_target_bits && | |||||
| bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){ | |||||
| choice--; | |||||
| this_bits=oggpack_bytes(vbi->packetblob[choice])*8; | |||||
| } | |||||
| }else if(bm->avg_reservoir+(this_bits-avg_target_bits)<desired_fill){ | |||||
| while(choice+1<PACKETBLOBS && this_bits<avg_target_bits && | |||||
| bm->avg_reservoir+(this_bits-avg_target_bits)<desired_fill){ | |||||
| choice++; | |||||
| this_bits=oggpack_bytes(vbi->packetblob[choice])*8; | |||||
| } | |||||
| } | |||||
| slew=rint(choice-bm->avgfloat)/samples*vi->rate; | |||||
| if(slew<-slewlimit)slew=-slewlimit; | |||||
| if(slew>slewlimit)slew=slewlimit; | |||||
| choice=rint(bm->avgfloat+= slew/vi->rate*samples); | |||||
| this_bits=oggpack_bytes(vbi->packetblob[choice])*8; | |||||
| } | |||||
| /* enforce min(if used) on the current floater (if used) */ | |||||
| if(bm->min_bitsper>0){ | |||||
| /* do we need to force the bitrate up? */ | |||||
| if(this_bits<min_target_bits){ | |||||
| while(bm->minmax_reservoir-(min_target_bits-this_bits)<0){ | |||||
| choice++; | |||||
| if(choice>=PACKETBLOBS)break; | |||||
| this_bits=oggpack_bytes(vbi->packetblob[choice])*8; | |||||
| } | |||||
| } | |||||
| } | |||||
| /* enforce max (if used) on the current floater (if used) */ | |||||
| if(bm->max_bitsper>0){ | |||||
| /* do we need to force the bitrate down? */ | |||||
| if(this_bits>max_target_bits){ | |||||
| while(bm->minmax_reservoir+(this_bits-max_target_bits)>bi->reservoir_bits){ | |||||
| choice--; | |||||
| if(choice<0)break; | |||||
| this_bits=oggpack_bytes(vbi->packetblob[choice])*8; | |||||
| } | |||||
| } | |||||
| } | |||||
| /* Choice of packetblobs now made based on floater, and min/max | |||||
| requirements. Now boundary check extreme choices */ | |||||
| if(choice<0){ | |||||
| /* choosing a smaller packetblob is insufficient to trim bitrate. | |||||
| frame will need to be truncated */ | |||||
| long maxsize=(max_target_bits+(bi->reservoir_bits-bm->minmax_reservoir))/8; | |||||
| bm->choice=choice=0; | |||||
| if(oggpack_bytes(vbi->packetblob[choice])>maxsize){ | |||||
| oggpack_writetrunc(vbi->packetblob[choice],maxsize*8); | |||||
| this_bits=oggpack_bytes(vbi->packetblob[choice])*8; | |||||
| } | |||||
| }else{ | |||||
| long minsize=(min_target_bits-bm->minmax_reservoir+7)/8; | |||||
| if(choice>=PACKETBLOBS) | |||||
| choice=PACKETBLOBS-1; | |||||
| bm->choice=choice; | |||||
| /* prop up bitrate according to demand. pad this frame out with zeroes */ | |||||
| minsize-=oggpack_bytes(vbi->packetblob[choice]); | |||||
| while(minsize-->0)oggpack_write(vbi->packetblob[choice],0,8); | |||||
| this_bits=oggpack_bytes(vbi->packetblob[choice])*8; | |||||
| } | |||||
| /* now we have the final packet and the final packet size. Update statistics */ | |||||
| /* min and max reservoir */ | |||||
| if(bm->min_bitsper>0 || bm->max_bitsper>0){ | |||||
| if(max_target_bits>0 && this_bits>max_target_bits){ | |||||
| bm->minmax_reservoir+=(this_bits-max_target_bits); | |||||
| }else if(min_target_bits>0 && this_bits<min_target_bits){ | |||||
| bm->minmax_reservoir+=(this_bits-min_target_bits); | |||||
| }else{ | |||||
| /* inbetween; we want to take reservoir toward but not past desired_fill */ | |||||
| if(bm->minmax_reservoir>desired_fill){ | |||||
| if(max_target_bits>0){ /* logical bulletproofing against initialization state */ | |||||
| bm->minmax_reservoir+=(this_bits-max_target_bits); | |||||
| if(bm->minmax_reservoir<desired_fill)bm->minmax_reservoir=desired_fill; | |||||
| }else{ | |||||
| bm->minmax_reservoir=desired_fill; | |||||
| } | |||||
| }else{ | |||||
| if(min_target_bits>0){ /* logical bulletproofing against initialization state */ | |||||
| bm->minmax_reservoir+=(this_bits-min_target_bits); | |||||
| if(bm->minmax_reservoir>desired_fill)bm->minmax_reservoir=desired_fill; | |||||
| }else{ | |||||
| bm->minmax_reservoir=desired_fill; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| /* avg reservoir */ | |||||
| if(bm->avg_bitsper>0){ | |||||
| long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper); | |||||
| bm->avg_reservoir+=this_bits-avg_target_bits; | |||||
| } | |||||
| return(0); | |||||
| } | |||||
| int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd,ogg_packet *op){ | |||||
| private_state *b=(private_state*)vd->backend_state; | |||||
| bitrate_manager_state *bm=&b->bms; | |||||
| vorbis_block *vb=bm->vb; | |||||
| int choice=PACKETBLOBS/2; | |||||
| if(!vb)return 0; | |||||
| if(op){ | |||||
| vorbis_block_internal *vbi=(vorbis_block_internal*)vb->internal; | |||||
| if(vorbis_bitrate_managed(vb)) | |||||
| choice=bm->choice; | |||||
| op->packet=oggpack_get_buffer(vbi->packetblob[choice]); | |||||
| op->bytes=oggpack_bytes(vbi->packetblob[choice]); | |||||
| op->b_o_s=0; | |||||
| op->e_o_s=vb->eofflag; | |||||
| op->granulepos=vb->granulepos; | |||||
| op->packetno=vb->sequence; /* for sake of completeness */ | |||||
| } | |||||
| bm->vb=0; | |||||
| return(1); | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,59 @@ | |||||
| /******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * | |||||
| * by the XIPHOPHORUS Company http://www.xiph.org/ * | |||||
| * * | |||||
| ******************************************************************** | |||||
| function: bitrate tracking and management | |||||
| last mod: $Id: bitrate.h,v 1.1 2007/06/07 17:49:17 jules_rms Exp $ | |||||
| ********************************************************************/ | |||||
| #ifndef _V_BITRATE_H_ | |||||
| #define _V_BITRATE_H_ | |||||
| #include "../../codec.h" | |||||
| #include "codec_internal.h" | |||||
| #include "os.h" | |||||
| /* encode side bitrate tracking */ | |||||
| typedef struct bitrate_manager_state { | |||||
| int managed; | |||||
| long avg_reservoir; | |||||
| long minmax_reservoir; | |||||
| long avg_bitsper; | |||||
| long min_bitsper; | |||||
| long max_bitsper; | |||||
| long short_per_long; | |||||
| double avgfloat; | |||||
| vorbis_block *vb; | |||||
| int choice; | |||||
| } bitrate_manager_state; | |||||
| typedef struct bitrate_manager_info{ | |||||
| long avg_rate; | |||||
| long min_rate; | |||||
| long max_rate; | |||||
| long reservoir_bits; | |||||
| double reservoir_bias; | |||||
| double slew_damp; | |||||
| } bitrate_manager_info; | |||||
| extern void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bs); | |||||
| extern void vorbis_bitrate_clear(bitrate_manager_state *bs); | |||||
| extern int vorbis_bitrate_managed(vorbis_block *vb); | |||||
| extern int vorbis_bitrate_addblock(vorbis_block *vb); | |||||
| extern int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd, ogg_packet *op); | |||||
| #endif | |||||
| @@ -0,0 +1,983 @@ | |||||
| /******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2003 * | |||||
| * by the XIPHOPHORUS Company http://www.xiph.org/ * | |||||
| * * | |||||
| ******************************************************************** | |||||
| function: PCM data vector blocking, windowing and dis/reassembly | |||||
| last mod: $Id: block.c,v 1.1 2007/06/07 17:49:17 jules_rms Exp $ | |||||
| Handle windowing, overlap-add, etc of the PCM vectors. This is made | |||||
| more amusing by Vorbis' current two allowed block sizes. | |||||
| ********************************************************************/ | |||||
| #include "../../juce_OggVorbisHeader.h" | |||||
| #if JUCE_USE_OGGVORBIS | |||||
| #include <stdio.h> | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| #include "../../ogg.h" | |||||
| #include "../../codec.h" | |||||
| #include "codec_internal.h" | |||||
| #include "window.h" | |||||
| #include "mdct.h" | |||||
| #include "lpc.h" | |||||
| #include "registry.h" | |||||
| #include "misc.h" | |||||
| /* pcm accumulator examples (not exhaustive): | |||||
| <-------------- lW ----------------> | |||||
| <--------------- W ----------------> | |||||
| : .....|..... _______________ | | |||||
| : .''' | '''_--- | |\ | | |||||
| :.....''' |_____--- '''......| | \_______| | |||||
| :.................|__________________|_______|__|______| | |||||
| |<------ Sl ------>| > Sr < |endW | |||||
| |beginSl |endSl | |endSr | |||||
| |beginW |endlW |beginSr | |||||
| |< lW >| | |||||
| <--------------- W ----------------> | |||||
| | | .. ______________ | | |||||
| | | ' `/ | ---_ | | |||||
| |___.'___/`. | ---_____| | |||||
| |_______|__|_______|_________________| | |||||
| | >|Sl|< |<------ Sr ----->|endW | |||||
| | | |endSl |beginSr |endSr | |||||
| |beginW | |endlW | |||||
| mult[0] |beginSl mult[n] | |||||
| <-------------- lW -----------------> | |||||
| |<--W-->| | |||||
| : .............. ___ | | | |||||
| : .''' |`/ \ | | | |||||
| :.....''' |/`....\|...| | |||||
| :.........................|___|___|___| | |||||
| |Sl |Sr |endW | |||||
| | | |endSr | |||||
| | |beginSr | |||||
| | |endSl | |||||
| |beginSl | |||||
| |beginW | |||||
| */ | |||||
| /* block abstraction setup *********************************************/ | |||||
| #ifndef WORD_ALIGN | |||||
| #define WORD_ALIGN 8 | |||||
| #endif | |||||
| int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){ | |||||
| int i; | |||||
| memset(vb,0,sizeof(*vb)); | |||||
| vb->vd=v; | |||||
| vb->localalloc=0; | |||||
| vb->localstore=NULL; | |||||
| if(v->analysisp){ | |||||
| vorbis_block_internal *vbi=(vorbis_block_internal*) | |||||
| (vb->internal=(vorbis_block_internal*)_ogg_calloc(1,sizeof(vorbis_block_internal))); | |||||
| vbi->ampmax=-9999; | |||||
| for(i=0;i<PACKETBLOBS;i++){ | |||||
| if(i==PACKETBLOBS/2){ | |||||
| vbi->packetblob[i]=&vb->opb; | |||||
| }else{ | |||||
| vbi->packetblob[i]= | |||||
| (oggpack_buffer*) _ogg_calloc(1,sizeof(oggpack_buffer)); | |||||
| } | |||||
| oggpack_writeinit(vbi->packetblob[i]); | |||||
| } | |||||
| } | |||||
| return(0); | |||||
| } | |||||
| void *_vorbis_block_alloc(vorbis_block *vb,long bytes){ | |||||
| bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1); | |||||
| if(bytes+vb->localtop>vb->localalloc){ | |||||
| /* can't just _ogg_realloc... there are outstanding pointers */ | |||||
| if(vb->localstore){ | |||||
| struct alloc_chain *link=(struct alloc_chain*)_ogg_malloc(sizeof(*link)); | |||||
| vb->totaluse+=vb->localtop; | |||||
| link->next=vb->reap; | |||||
| link->ptr=vb->localstore; | |||||
| vb->reap=link; | |||||
| } | |||||
| /* highly conservative */ | |||||
| vb->localalloc=bytes; | |||||
| vb->localstore=_ogg_malloc(vb->localalloc); | |||||
| vb->localtop=0; | |||||
| } | |||||
| { | |||||
| void *ret=(void *)(((char *)vb->localstore)+vb->localtop); | |||||
| vb->localtop+=bytes; | |||||
| return ret; | |||||
| } | |||||
| } | |||||
| /* reap the chain, pull the ripcord */ | |||||
| void _vorbis_block_ripcord(vorbis_block *vb){ | |||||
| /* reap the chain */ | |||||
| struct alloc_chain *reap=vb->reap; | |||||
| while(reap){ | |||||
| struct alloc_chain *next=reap->next; | |||||
| _ogg_free(reap->ptr); | |||||
| memset(reap,0,sizeof(*reap)); | |||||
| _ogg_free(reap); | |||||
| reap=next; | |||||
| } | |||||
| /* consolidate storage */ | |||||
| if(vb->totaluse){ | |||||
| vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc); | |||||
| vb->localalloc+=vb->totaluse; | |||||
| vb->totaluse=0; | |||||
| } | |||||
| /* pull the ripcord */ | |||||
| vb->localtop=0; | |||||
| vb->reap=NULL; | |||||
| } | |||||
| int vorbis_block_clear(vorbis_block *vb){ | |||||
| int i; | |||||
| vorbis_block_internal *vbi=(vorbis_block_internal*)vb->internal; | |||||
| _vorbis_block_ripcord(vb); | |||||
| if(vb->localstore)_ogg_free(vb->localstore); | |||||
| if(vbi){ | |||||
| for(i=0;i<PACKETBLOBS;i++){ | |||||
| oggpack_writeclear(vbi->packetblob[i]); | |||||
| if(i!=PACKETBLOBS/2)_ogg_free(vbi->packetblob[i]); | |||||
| } | |||||
| _ogg_free(vbi); | |||||
| } | |||||
| memset(vb,0,sizeof(*vb)); | |||||
| return(0); | |||||
| } | |||||
| /* Analysis side code, but directly related to blocking. Thus it's | |||||
| here and not in analysis.c (which is for analysis transforms only). | |||||
| The init is here because some of it is shared */ | |||||
| static int _vds_shared_init(vorbis_dsp_state *v,vorbis_info *vi,int encp){ | |||||
| int i; | |||||
| codec_setup_info *ci=(codec_setup_info*)vi->codec_setup; | |||||
| private_state *b=NULL; | |||||
| int hs; | |||||
| if(ci==NULL) return 1; | |||||
| hs=ci->halfrate_flag; | |||||
| memset(v,0,sizeof(*v)); | |||||
| b=(private_state*) (v->backend_state=(private_state*)_ogg_calloc(1,sizeof(*b))); | |||||
| v->vi=vi; | |||||
| b->modebits=ilog2(ci->modes); | |||||
| b->transform[0]=(vorbis_look_transform**)_ogg_calloc(VI_TRANSFORMB,sizeof(*b->transform[0])); | |||||
| b->transform[1]=(vorbis_look_transform**)_ogg_calloc(VI_TRANSFORMB,sizeof(*b->transform[1])); | |||||
| /* MDCT is tranform 0 */ | |||||
| b->transform[0][0]=_ogg_calloc(1,sizeof(mdct_lookup)); | |||||
| b->transform[1][0]=_ogg_calloc(1,sizeof(mdct_lookup)); | |||||
| mdct_init((mdct_lookup*)b->transform[0][0],ci->blocksizes[0]>>hs); | |||||
| mdct_init((mdct_lookup*)b->transform[1][0],ci->blocksizes[1]>>hs); | |||||
| /* Vorbis I uses only window type 0 */ | |||||
| b->window[0]=ilog2(ci->blocksizes[0])-6; | |||||
| b->window[1]=ilog2(ci->blocksizes[1])-6; | |||||
| if(encp){ /* encode/decode differ here */ | |||||
| /* analysis always needs an fft */ | |||||
| drft_init(&b->fft_look[0],ci->blocksizes[0]); | |||||
| drft_init(&b->fft_look[1],ci->blocksizes[1]); | |||||
| /* finish the codebooks */ | |||||
| if(!ci->fullbooks){ | |||||
| ci->fullbooks=(codebook*) _ogg_calloc(ci->books,sizeof(*ci->fullbooks)); | |||||
| for(i=0;i<ci->books;i++) | |||||
| vorbis_book_init_encode(ci->fullbooks+i,ci->book_param[i]); | |||||
| } | |||||
| b->psy=(vorbis_look_psy*)_ogg_calloc(ci->psys,sizeof(*b->psy)); | |||||
| for(i=0;i<ci->psys;i++){ | |||||
| _vp_psy_init(b->psy+i, | |||||
| ci->psy_param[i], | |||||
| &ci->psy_g_param, | |||||
| ci->blocksizes[ci->psy_param[i]->blockflag]/2, | |||||
| vi->rate); | |||||
| } | |||||
| v->analysisp=1; | |||||
| }else{ | |||||
| /* finish the codebooks */ | |||||
| if(!ci->fullbooks){ | |||||
| ci->fullbooks=(codebook*) _ogg_calloc(ci->books,sizeof(*ci->fullbooks)); | |||||
| for(i=0;i<ci->books;i++){ | |||||
| vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]); | |||||
| /* decode codebooks are now standalone after init */ | |||||
| vorbis_staticbook_destroy(ci->book_param[i]); | |||||
| ci->book_param[i]=NULL; | |||||
| } | |||||
| } | |||||
| } | |||||
| /* initialize the storage vectors. blocksize[1] is small for encode, | |||||
| but the correct size for decode */ | |||||
| v->pcm_storage=ci->blocksizes[1]; | |||||
| v->pcm=(float**)_ogg_malloc(vi->channels*sizeof(*v->pcm)); | |||||
| v->pcmret=(float**)_ogg_malloc(vi->channels*sizeof(*v->pcmret)); | |||||
| { | |||||
| int i; | |||||
| for(i=0;i<vi->channels;i++) | |||||
| v->pcm[i]=(float*)_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i])); | |||||
| } | |||||
| /* all 1 (large block) or 0 (small block) */ | |||||
| /* explicitly set for the sake of clarity */ | |||||
| v->lW=0; /* previous window size */ | |||||
| v->W=0; /* current window size */ | |||||
| /* all vector indexes */ | |||||
| v->centerW=ci->blocksizes[1]/2; | |||||
| v->pcm_current=v->centerW; | |||||
| /* initialize all the backend lookups */ | |||||
| b->flr=(vorbis_look_floor**)_ogg_calloc(ci->floors,sizeof(*b->flr)); | |||||
| b->residue=(vorbis_look_residue**)_ogg_calloc(ci->residues,sizeof(*b->residue)); | |||||
| for(i=0;i<ci->floors;i++) | |||||
| b->flr[i]=_floor_P[ci->floor_type[i]]-> | |||||
| look(v,ci->floor_param[i]); | |||||
| for(i=0;i<ci->residues;i++) | |||||
| b->residue[i]=_residue_P[ci->residue_type[i]]-> | |||||
| look(v,ci->residue_param[i]); | |||||
| return 0; | |||||
| } | |||||
| /* arbitrary settings and spec-mandated numbers get filled in here */ | |||||
| int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi){ | |||||
| private_state *b=NULL; | |||||
| if(_vds_shared_init(v,vi,1))return 1; | |||||
| b=(private_state*)v->backend_state; | |||||
| b->psy_g_look=_vp_global_look(vi); | |||||
| /* Initialize the envelope state storage */ | |||||
| b->ve=(envelope_lookup*)_ogg_calloc(1,sizeof(*b->ve)); | |||||
| _ve_envelope_init(b->ve,vi); | |||||
| vorbis_bitrate_init(vi,&b->bms); | |||||
| /* compressed audio packets start after the headers | |||||
| with sequence number 3 */ | |||||
| v->sequence=3; | |||||
| return(0); | |||||
| } | |||||
| void vorbis_dsp_clear(vorbis_dsp_state *v){ | |||||
| int i; | |||||
| if(v){ | |||||
| vorbis_info *vi=v->vi; | |||||
| codec_setup_info *ci=(codec_setup_info*)(vi?vi->codec_setup:NULL); | |||||
| private_state *b=(private_state*)v->backend_state; | |||||
| if(b){ | |||||
| if(b->ve){ | |||||
| _ve_envelope_clear(b->ve); | |||||
| _ogg_free(b->ve); | |||||
| } | |||||
| if(b->transform[0]){ | |||||
| mdct_clear((mdct_lookup*) b->transform[0][0]); | |||||
| _ogg_free(b->transform[0][0]); | |||||
| _ogg_free(b->transform[0]); | |||||
| } | |||||
| if(b->transform[1]){ | |||||
| mdct_clear((mdct_lookup*) b->transform[1][0]); | |||||
| _ogg_free(b->transform[1][0]); | |||||
| _ogg_free(b->transform[1]); | |||||
| } | |||||
| if(b->flr){ | |||||
| for(i=0;i<ci->floors;i++) | |||||
| _floor_P[ci->floor_type[i]]-> | |||||
| free_look(b->flr[i]); | |||||
| _ogg_free(b->flr); | |||||
| } | |||||
| if(b->residue){ | |||||
| for(i=0;i<ci->residues;i++) | |||||
| _residue_P[ci->residue_type[i]]-> | |||||
| free_look(b->residue[i]); | |||||
| _ogg_free(b->residue); | |||||
| } | |||||
| if(b->psy){ | |||||
| for(i=0;i<ci->psys;i++) | |||||
| _vp_psy_clear(b->psy+i); | |||||
| _ogg_free(b->psy); | |||||
| } | |||||
| if(b->psy_g_look)_vp_global_free(b->psy_g_look); | |||||
| vorbis_bitrate_clear(&b->bms); | |||||
| drft_clear(&b->fft_look[0]); | |||||
| drft_clear(&b->fft_look[1]); | |||||
| } | |||||
| if(v->pcm){ | |||||
| for(i=0;i<vi->channels;i++) | |||||
| if(v->pcm[i])_ogg_free(v->pcm[i]); | |||||
| _ogg_free(v->pcm); | |||||
| if(v->pcmret)_ogg_free(v->pcmret); | |||||
| } | |||||
| if(b){ | |||||
| /* free header, header1, header2 */ | |||||
| if(b->header)_ogg_free(b->header); | |||||
| if(b->header1)_ogg_free(b->header1); | |||||
| if(b->header2)_ogg_free(b->header2); | |||||
| _ogg_free(b); | |||||
| } | |||||
| memset(v,0,sizeof(*v)); | |||||
| } | |||||
| } | |||||
| float **vorbis_analysis_buffer(vorbis_dsp_state *v, int vals){ | |||||
| int i; | |||||
| vorbis_info *vi=v->vi; | |||||
| private_state *b=(private_state*)v->backend_state; | |||||
| /* free header, header1, header2 */ | |||||
| if(b->header)_ogg_free(b->header);b->header=NULL; | |||||
| if(b->header1)_ogg_free(b->header1);b->header1=NULL; | |||||
| if(b->header2)_ogg_free(b->header2);b->header2=NULL; | |||||
| /* Do we have enough storage space for the requested buffer? If not, | |||||
| expand the PCM (and envelope) storage */ | |||||
| if(v->pcm_current+vals>=v->pcm_storage){ | |||||
| v->pcm_storage=v->pcm_current+vals*2; | |||||
| for(i=0;i<vi->channels;i++){ | |||||
| v->pcm[i]=(float*)_ogg_realloc(v->pcm[i],v->pcm_storage*sizeof(*v->pcm[i])); | |||||
| } | |||||
| } | |||||
| for(i=0;i<vi->channels;i++) | |||||
| v->pcmret[i]=v->pcm[i]+v->pcm_current; | |||||
| return(v->pcmret); | |||||
| } | |||||
| static void _preextrapolate_helper(vorbis_dsp_state *v){ | |||||
| int i; | |||||
| int order=32; | |||||
| float *lpc=(float*)alloca(order*sizeof(*lpc)); | |||||
| float *work=(float*)alloca(v->pcm_current*sizeof(*work)); | |||||
| long j; | |||||
| v->preextrapolate=1; | |||||
| if(v->pcm_current-v->centerW>order*2){ /* safety */ | |||||
| for(i=0;i<v->vi->channels;i++){ | |||||
| /* need to run the extrapolation in reverse! */ | |||||
| for(j=0;j<v->pcm_current;j++) | |||||
| work[j]=v->pcm[i][v->pcm_current-j-1]; | |||||
| /* prime as above */ | |||||
| vorbis_lpc_from_data(work,lpc,v->pcm_current-v->centerW,order); | |||||
| /* run the predictor filter */ | |||||
| vorbis_lpc_predict(lpc,work+v->pcm_current-v->centerW-order, | |||||
| order, | |||||
| work+v->pcm_current-v->centerW, | |||||
| v->centerW); | |||||
| for(j=0;j<v->pcm_current;j++) | |||||
| v->pcm[i][v->pcm_current-j-1]=work[j]; | |||||
| } | |||||
| } | |||||
| } | |||||
| /* call with val<=0 to set eof */ | |||||
| int vorbis_analysis_wrote(vorbis_dsp_state *v, int vals){ | |||||
| vorbis_info *vi=v->vi; | |||||
| codec_setup_info *ci=(codec_setup_info*)vi->codec_setup; | |||||
| if(vals<=0){ | |||||
| int order=32; | |||||
| int i; | |||||
| float *lpc=(float*) alloca(order*sizeof(*lpc)); | |||||
| /* if it wasn't done earlier (very short sample) */ | |||||
| if(!v->preextrapolate) | |||||
| _preextrapolate_helper(v); | |||||
| /* We're encoding the end of the stream. Just make sure we have | |||||
| [at least] a few full blocks of zeroes at the end. */ | |||||
| /* actually, we don't want zeroes; that could drop a large | |||||
| amplitude off a cliff, creating spread spectrum noise that will | |||||
| suck to encode. Extrapolate for the sake of cleanliness. */ | |||||
| vorbis_analysis_buffer(v,ci->blocksizes[1]*3); | |||||
| v->eofflag=v->pcm_current; | |||||
| v->pcm_current+=ci->blocksizes[1]*3; | |||||
| for(i=0;i<vi->channels;i++){ | |||||
| if(v->eofflag>order*2){ | |||||
| /* extrapolate with LPC to fill in */ | |||||
| long n; | |||||
| /* make a predictor filter */ | |||||
| n=v->eofflag; | |||||
| if(n>ci->blocksizes[1])n=ci->blocksizes[1]; | |||||
| vorbis_lpc_from_data(v->pcm[i]+v->eofflag-n,lpc,n,order); | |||||
| /* run the predictor filter */ | |||||
| vorbis_lpc_predict(lpc,v->pcm[i]+v->eofflag-order,order, | |||||
| v->pcm[i]+v->eofflag,v->pcm_current-v->eofflag); | |||||
| }else{ | |||||
| /* not enough data to extrapolate (unlikely to happen due to | |||||
| guarding the overlap, but bulletproof in case that | |||||
| assumtion goes away). zeroes will do. */ | |||||
| memset(v->pcm[i]+v->eofflag,0, | |||||
| (v->pcm_current-v->eofflag)*sizeof(*v->pcm[i])); | |||||
| } | |||||
| } | |||||
| }else{ | |||||
| if(v->pcm_current+vals>v->pcm_storage) | |||||
| return(OV_EINVAL); | |||||
| v->pcm_current+=vals; | |||||
| /* we may want to reverse extrapolate the beginning of a stream | |||||
| too... in case we're beginning on a cliff! */ | |||||
| /* clumsy, but simple. It only runs once, so simple is good. */ | |||||
| if(!v->preextrapolate && v->pcm_current-v->centerW>ci->blocksizes[1]) | |||||
| _preextrapolate_helper(v); | |||||
| } | |||||
| return(0); | |||||
| } | |||||
| /* do the deltas, envelope shaping, pre-echo and determine the size of | |||||
| the next block on which to continue analysis */ | |||||
| int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){ | |||||
| int i; | |||||
| vorbis_info *vi=v->vi; | |||||
| codec_setup_info *ci=(codec_setup_info*)vi->codec_setup; | |||||
| private_state *b=(private_state*)v->backend_state; | |||||
| vorbis_look_psy_global *g=b->psy_g_look; | |||||
| long beginW=v->centerW-ci->blocksizes[v->W]/2,centerNext; | |||||
| vorbis_block_internal *vbi=(vorbis_block_internal *)vb->internal; | |||||
| /* check to see if we're started... */ | |||||
| if(!v->preextrapolate)return(0); | |||||
| /* check to see if we're done... */ | |||||
| if(v->eofflag==-1)return(0); | |||||
| /* By our invariant, we have lW, W and centerW set. Search for | |||||
| the next boundary so we can determine nW (the next window size) | |||||
| which lets us compute the shape of the current block's window */ | |||||
| /* we do an envelope search even on a single blocksize; we may still | |||||
| be throwing more bits at impulses, and envelope search handles | |||||
| marking impulses too. */ | |||||
| { | |||||
| long bp=_ve_envelope_search(v); | |||||
| if(bp==-1){ | |||||
| if(v->eofflag==0)return(0); /* not enough data currently to search for a | |||||
| full long block */ | |||||
| v->nW=0; | |||||
| }else{ | |||||
| if(ci->blocksizes[0]==ci->blocksizes[1]) | |||||
| v->nW=0; | |||||
| else | |||||
| v->nW=bp; | |||||
| } | |||||
| } | |||||
| centerNext=v->centerW+ci->blocksizes[v->W]/4+ci->blocksizes[v->nW]/4; | |||||
| { | |||||
| /* center of next block + next block maximum right side. */ | |||||
| long blockbound=centerNext+ci->blocksizes[v->nW]/2; | |||||
| if(v->pcm_current<blockbound)return(0); /* not enough data yet; | |||||
| although this check is | |||||
| less strict that the | |||||
| _ve_envelope_search, | |||||
| the search is not run | |||||
| if we only use one | |||||
| block size */ | |||||
| } | |||||
| /* fill in the block. Note that for a short window, lW and nW are *short* | |||||
| regardless of actual settings in the stream */ | |||||
| _vorbis_block_ripcord(vb); | |||||
| vb->lW=v->lW; | |||||
| vb->W=v->W; | |||||
| vb->nW=v->nW; | |||||
| if(v->W){ | |||||
| if(!v->lW || !v->nW){ | |||||
| vbi->blocktype=BLOCKTYPE_TRANSITION; | |||||
| /*fprintf(stderr,"-");*/ | |||||
| }else{ | |||||
| vbi->blocktype=BLOCKTYPE_LONG; | |||||
| /*fprintf(stderr,"_");*/ | |||||
| } | |||||
| }else{ | |||||
| if(_ve_envelope_mark(v)){ | |||||
| vbi->blocktype=BLOCKTYPE_IMPULSE; | |||||
| /*fprintf(stderr,"|");*/ | |||||
| }else{ | |||||
| vbi->blocktype=BLOCKTYPE_PADDING; | |||||
| /*fprintf(stderr,".");*/ | |||||
| } | |||||
| } | |||||
| vb->vd=v; | |||||
| vb->sequence=v->sequence++; | |||||
| vb->granulepos=v->granulepos; | |||||
| vb->pcmend=ci->blocksizes[v->W]; | |||||
| /* copy the vectors; this uses the local storage in vb */ | |||||
| /* this tracks 'strongest peak' for later psychoacoustics */ | |||||
| /* moved to the global psy state; clean this mess up */ | |||||
| if(vbi->ampmax>g->ampmax)g->ampmax=vbi->ampmax; | |||||
| g->ampmax=_vp_ampmax_decay(g->ampmax,v); | |||||
| vbi->ampmax=g->ampmax; | |||||
| vb->pcm=(float**)_vorbis_block_alloc(vb,sizeof(*vb->pcm)*vi->channels); | |||||
| vbi->pcmdelay=(float**)_vorbis_block_alloc(vb,sizeof(*vbi->pcmdelay)*vi->channels); | |||||
| for(i=0;i<vi->channels;i++){ | |||||
| vbi->pcmdelay[i]= | |||||
| (float*) _vorbis_block_alloc(vb,(vb->pcmend+beginW)*sizeof(*vbi->pcmdelay[i])); | |||||
| memcpy(vbi->pcmdelay[i],v->pcm[i],(vb->pcmend+beginW)*sizeof(*vbi->pcmdelay[i])); | |||||
| vb->pcm[i]=vbi->pcmdelay[i]+beginW; | |||||
| /* before we added the delay | |||||
| vb->pcm[i]=_vorbis_block_alloc(vb,vb->pcmend*sizeof(*vb->pcm[i])); | |||||
| memcpy(vb->pcm[i],v->pcm[i]+beginW,ci->blocksizes[v->W]*sizeof(*vb->pcm[i])); | |||||
| */ | |||||
| } | |||||
| /* handle eof detection: eof==0 means that we've not yet received EOF | |||||
| eof>0 marks the last 'real' sample in pcm[] | |||||
| eof<0 'no more to do'; doesn't get here */ | |||||
| if(v->eofflag){ | |||||
| if(v->centerW>=v->eofflag){ | |||||
| v->eofflag=-1; | |||||
| vb->eofflag=1; | |||||
| return(1); | |||||
| } | |||||
| } | |||||
| /* advance storage vectors and clean up */ | |||||
| { | |||||
| int new_centerNext=ci->blocksizes[1]/2; | |||||
| int movementW=centerNext-new_centerNext; | |||||
| if(movementW>0){ | |||||
| _ve_envelope_shift(b->ve,movementW); | |||||
| v->pcm_current-=movementW; | |||||
| for(i=0;i<vi->channels;i++) | |||||
| memmove(v->pcm[i],v->pcm[i]+movementW, | |||||
| v->pcm_current*sizeof(*v->pcm[i])); | |||||
| v->lW=v->W; | |||||
| v->W=v->nW; | |||||
| v->centerW=new_centerNext; | |||||
| if(v->eofflag){ | |||||
| v->eofflag-=movementW; | |||||
| if(v->eofflag<=0)v->eofflag=-1; | |||||
| /* do not add padding to end of stream! */ | |||||
| if(v->centerW>=v->eofflag){ | |||||
| v->granulepos+=movementW-(v->centerW-v->eofflag); | |||||
| }else{ | |||||
| v->granulepos+=movementW; | |||||
| } | |||||
| }else{ | |||||
| v->granulepos+=movementW; | |||||
| } | |||||
| } | |||||
| } | |||||
| /* done */ | |||||
| return(1); | |||||
| } | |||||
| int vorbis_synthesis_restart(vorbis_dsp_state *v){ | |||||
| vorbis_info *vi=v->vi; | |||||
| codec_setup_info *ci; | |||||
| int hs; | |||||
| if(!v->backend_state)return -1; | |||||
| if(!vi)return -1; | |||||
| ci=(codec_setup_info*) vi->codec_setup; | |||||
| if(!ci)return -1; | |||||
| hs=ci->halfrate_flag; | |||||
| v->centerW=ci->blocksizes[1]>>(hs+1); | |||||
| v->pcm_current=v->centerW>>hs; | |||||
| v->pcm_returned=-1; | |||||
| v->granulepos=-1; | |||||
| v->sequence=-1; | |||||
| v->eofflag=0; | |||||
| ((private_state *)(v->backend_state))->sample_count=-1; | |||||
| return(0); | |||||
| } | |||||
| int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){ | |||||
| if(_vds_shared_init(v,vi,0)) return 1; | |||||
| vorbis_synthesis_restart(v); | |||||
| return 0; | |||||
| } | |||||
| /* Unlike in analysis, the window is only partially applied for each | |||||
| block. The time domain envelope is not yet handled at the point of | |||||
| calling (as it relies on the previous block). */ | |||||
| int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){ | |||||
| vorbis_info *vi=v->vi; | |||||
| codec_setup_info *ci=(codec_setup_info*)vi->codec_setup; | |||||
| private_state *b=(private_state*)v->backend_state; | |||||
| int hs=ci->halfrate_flag; | |||||
| int i,j; | |||||
| if(!vb)return(OV_EINVAL); | |||||
| if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL); | |||||
| v->lW=v->W; | |||||
| v->W=vb->W; | |||||
| v->nW=-1; | |||||
| if((v->sequence==-1)|| | |||||
| (v->sequence+1 != vb->sequence)){ | |||||
| v->granulepos=-1; /* out of sequence; lose count */ | |||||
| b->sample_count=-1; | |||||
| } | |||||
| v->sequence=vb->sequence; | |||||
| if(vb->pcm){ /* no pcm to process if vorbis_synthesis_trackonly | |||||
| was called on block */ | |||||
| int n=ci->blocksizes[v->W]>>(hs+1); | |||||
| int n0=ci->blocksizes[0]>>(hs+1); | |||||
| int n1=ci->blocksizes[1]>>(hs+1); | |||||
| int thisCenter; | |||||
| int prevCenter; | |||||
| v->glue_bits+=vb->glue_bits; | |||||
| v->time_bits+=vb->time_bits; | |||||
| v->floor_bits+=vb->floor_bits; | |||||
| v->res_bits+=vb->res_bits; | |||||
| if(v->centerW){ | |||||
| thisCenter=n1; | |||||
| prevCenter=0; | |||||
| }else{ | |||||
| thisCenter=0; | |||||
| prevCenter=n1; | |||||
| } | |||||
| /* v->pcm is now used like a two-stage double buffer. We don't want | |||||
| to have to constantly shift *or* adjust memory usage. Don't | |||||
| accept a new block until the old is shifted out */ | |||||
| for(j=0;j<vi->channels;j++){ | |||||
| /* the overlap/add section */ | |||||
| if(v->lW){ | |||||
| if(v->W){ | |||||
| /* large/large */ | |||||
| float *w=_vorbis_window_get(b->window[1]-hs); | |||||
| float *pcm=v->pcm[j]+prevCenter; | |||||
| float *p=vb->pcm[j]; | |||||
| for(i=0;i<n1;i++) | |||||
| pcm[i]=pcm[i]*w[n1-i-1] + p[i]*w[i]; | |||||
| }else{ | |||||
| /* large/small */ | |||||
| float *w=_vorbis_window_get(b->window[0]-hs); | |||||
| float *pcm=v->pcm[j]+prevCenter+n1/2-n0/2; | |||||
| float *p=vb->pcm[j]; | |||||
| for(i=0;i<n0;i++) | |||||
| pcm[i]=pcm[i]*w[n0-i-1] +p[i]*w[i]; | |||||
| } | |||||
| }else{ | |||||
| if(v->W){ | |||||
| /* small/large */ | |||||
| float *w=_vorbis_window_get(b->window[0]-hs); | |||||
| float *pcm=v->pcm[j]+prevCenter; | |||||
| float *p=vb->pcm[j]+n1/2-n0/2; | |||||
| for(i=0;i<n0;i++) | |||||
| pcm[i]=pcm[i]*w[n0-i-1] +p[i]*w[i]; | |||||
| for(;i<n1/2+n0/2;i++) | |||||
| pcm[i]=p[i]; | |||||
| }else{ | |||||
| /* small/small */ | |||||
| float *w=_vorbis_window_get(b->window[0]-hs); | |||||
| float *pcm=v->pcm[j]+prevCenter; | |||||
| float *p=vb->pcm[j]; | |||||
| for(i=0;i<n0;i++) | |||||
| pcm[i]=pcm[i]*w[n0-i-1] +p[i]*w[i]; | |||||
| } | |||||
| } | |||||
| /* the copy section */ | |||||
| { | |||||
| float *pcm=v->pcm[j]+thisCenter; | |||||
| float *p=vb->pcm[j]+n; | |||||
| for(i=0;i<n;i++) | |||||
| pcm[i]=p[i]; | |||||
| } | |||||
| } | |||||
| if(v->centerW) | |||||
| v->centerW=0; | |||||
| else | |||||
| v->centerW=n1; | |||||
| /* deal with initial packet state; we do this using the explicit | |||||
| pcm_returned==-1 flag otherwise we're sensitive to first block | |||||
| being short or long */ | |||||
| if(v->pcm_returned==-1){ | |||||
| v->pcm_returned=thisCenter; | |||||
| v->pcm_current=thisCenter; | |||||
| }else{ | |||||
| v->pcm_returned=prevCenter; | |||||
| v->pcm_current=prevCenter+ | |||||
| ((ci->blocksizes[v->lW]/4+ | |||||
| ci->blocksizes[v->W]/4)>>hs); | |||||
| } | |||||
| } | |||||
| /* track the frame number... This is for convenience, but also | |||||
| making sure our last packet doesn't end with added padding. If | |||||
| the last packet is partial, the number of samples we'll have to | |||||
| return will be past the vb->granulepos. | |||||
| This is not foolproof! It will be confused if we begin | |||||
| decoding at the last page after a seek or hole. In that case, | |||||
| we don't have a starting point to judge where the last frame | |||||
| is. For this reason, vorbisfile will always try to make sure | |||||
| it reads the last two marked pages in proper sequence */ | |||||
| if(b->sample_count==-1){ | |||||
| b->sample_count=0; | |||||
| }else{ | |||||
| b->sample_count+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4; | |||||
| } | |||||
| if(v->granulepos==-1){ | |||||
| if(vb->granulepos!=-1){ /* only set if we have a position to set to */ | |||||
| v->granulepos=vb->granulepos; | |||||
| /* is this a short page? */ | |||||
| if(b->sample_count>v->granulepos){ | |||||
| /* corner case; if this is both the first and last audio page, | |||||
| then spec says the end is cut, not beginning */ | |||||
| if(vb->eofflag){ | |||||
| /* trim the end */ | |||||
| /* no preceeding granulepos; assume we started at zero (we'd | |||||
| have to in a short single-page stream) */ | |||||
| /* granulepos could be -1 due to a seek, but that would result | |||||
| in a long count, not short count */ | |||||
| v->pcm_current-=(b->sample_count-v->granulepos)>>hs; | |||||
| }else{ | |||||
| /* trim the beginning */ | |||||
| v->pcm_returned+=(b->sample_count-v->granulepos)>>hs; | |||||
| if(v->pcm_returned>v->pcm_current) | |||||
| v->pcm_returned=v->pcm_current; | |||||
| } | |||||
| } | |||||
| } | |||||
| }else{ | |||||
| v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4; | |||||
| if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){ | |||||
| if(v->granulepos>vb->granulepos){ | |||||
| long extra=v->granulepos-vb->granulepos; | |||||
| if(extra) | |||||
| if(vb->eofflag){ | |||||
| /* partial last frame. Strip the extra samples off */ | |||||
| v->pcm_current-=extra>>hs; | |||||
| } /* else {Shouldn't happen *unless* the bitstream is out of | |||||
| spec. Either way, believe the bitstream } */ | |||||
| } /* else {Shouldn't happen *unless* the bitstream is out of | |||||
| spec. Either way, believe the bitstream } */ | |||||
| v->granulepos=vb->granulepos; | |||||
| } | |||||
| } | |||||
| /* Update, cleanup */ | |||||
| if(vb->eofflag)v->eofflag=1; | |||||
| return(0); | |||||
| } | |||||
| /* pcm==NULL indicates we just want the pending samples, no more */ | |||||
| int vorbis_synthesis_pcmout(vorbis_dsp_state *v,float ***pcm){ | |||||
| vorbis_info *vi=v->vi; | |||||
| if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){ | |||||
| if(pcm){ | |||||
| int i; | |||||
| for(i=0;i<vi->channels;i++) | |||||
| v->pcmret[i]=v->pcm[i]+v->pcm_returned; | |||||
| *pcm=v->pcmret; | |||||
| } | |||||
| return(v->pcm_current-v->pcm_returned); | |||||
| } | |||||
| return(0); | |||||
| } | |||||
| int vorbis_synthesis_read(vorbis_dsp_state *v,int n){ | |||||
| if(n && v->pcm_returned+n>v->pcm_current)return(OV_EINVAL); | |||||
| v->pcm_returned+=n; | |||||
| return(0); | |||||
| } | |||||
| /* intended for use with a specific vorbisfile feature; we want access | |||||
| to the [usually synthetic/postextrapolated] buffer and lapping at | |||||
| the end of a decode cycle, specifically, a half-short-block worth. | |||||
| This funtion works like pcmout above, except it will also expose | |||||
| this implicit buffer data not normally decoded. */ | |||||
| int vorbis_synthesis_lapout(vorbis_dsp_state *v,float ***pcm){ | |||||
| vorbis_info *vi=v->vi; | |||||
| codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; | |||||
| int hs=ci->halfrate_flag; | |||||
| int n=ci->blocksizes[v->W]>>(hs+1); | |||||
| int n0=ci->blocksizes[0]>>(hs+1); | |||||
| int n1=ci->blocksizes[1]>>(hs+1); | |||||
| int i,j; | |||||
| if(v->pcm_returned<0)return 0; | |||||
| /* our returned data ends at pcm_returned; because the synthesis pcm | |||||
| buffer is a two-fragment ring, that means our data block may be | |||||
| fragmented by buffering, wrapping or a short block not filling | |||||
| out a buffer. To simplify things, we unfragment if it's at all | |||||
| possibly needed. Otherwise, we'd need to call lapout more than | |||||
| once as well as hold additional dsp state. Opt for | |||||
| simplicity. */ | |||||
| /* centerW was advanced by blockin; it would be the center of the | |||||
| *next* block */ | |||||
| if(v->centerW==n1){ | |||||
| /* the data buffer wraps; swap the halves */ | |||||
| /* slow, sure, small */ | |||||
| for(j=0;j<vi->channels;j++){ | |||||
| float *p=v->pcm[j]; | |||||
| for(i=0;i<n1;i++){ | |||||
| float temp=p[i]; | |||||
| p[i]=p[i+n1]; | |||||
| p[i+n1]=temp; | |||||
| } | |||||
| } | |||||
| v->pcm_current-=n1; | |||||
| v->pcm_returned-=n1; | |||||
| v->centerW=0; | |||||
| } | |||||
| /* solidify buffer into contiguous space */ | |||||
| if((v->lW^v->W)==1){ | |||||
| /* long/short or short/long */ | |||||
| for(j=0;j<vi->channels;j++){ | |||||
| float *s=v->pcm[j]; | |||||
| float *d=v->pcm[j]+(n1-n0)/2; | |||||
| for(i=(n1+n0)/2-1;i>=0;--i) | |||||
| d[i]=s[i]; | |||||
| } | |||||
| v->pcm_returned+=(n1-n0)/2; | |||||
| v->pcm_current+=(n1-n0)/2; | |||||
| }else{ | |||||
| if(v->lW==0){ | |||||
| /* short/short */ | |||||
| for(j=0;j<vi->channels;j++){ | |||||
| float *s=v->pcm[j]; | |||||
| float *d=v->pcm[j]+n1-n0; | |||||
| for(i=n0-1;i>=0;--i) | |||||
| d[i]=s[i]; | |||||
| } | |||||
| v->pcm_returned+=n1-n0; | |||||
| v->pcm_current+=n1-n0; | |||||
| } | |||||
| } | |||||
| if(pcm){ | |||||
| int i; | |||||
| for(i=0;i<vi->channels;i++) | |||||
| v->pcmret[i]=v->pcm[i]+v->pcm_returned; | |||||
| *pcm=v->pcmret; | |||||
| } | |||||
| return(n1+n-v->pcm_returned); | |||||
| } | |||||
| float *vorbis_window(vorbis_dsp_state *v,int W){ | |||||
| vorbis_info *vi=v->vi; | |||||
| codec_setup_info *ci=(codec_setup_info*) vi->codec_setup; | |||||
| int hs=ci->halfrate_flag; | |||||
| private_state *b=(private_state*)v->backend_state; | |||||
| if(b->window[W]-1<0)return NULL; | |||||
| return _vorbis_window_get(b->window[W]-hs); | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,614 @@ | |||||
| /******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * | |||||
| * by the XIPHOPHORUS Company http://www.xiph.org/ * | |||||
| * * | |||||
| ******************************************************************** | |||||
| function: basic codebook pack/unpack/code/decode operations | |||||
| last mod: $Id: codebook.c,v 1.1 2007/06/07 17:49:17 jules_rms Exp $ | |||||
| ********************************************************************/ | |||||
| #include "../../juce_OggVorbisHeader.h" | |||||
| #if JUCE_USE_OGGVORBIS | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| #include <math.h> | |||||
| #include "../../ogg.h" | |||||
| #include "../../codec.h" | |||||
| #include "codebook.h" | |||||
| #include "scales.h" | |||||
| #include "misc.h" | |||||
| #include "os.h" | |||||
| /* packs the given codebook into the bitstream **************************/ | |||||
| int vorbis_staticbook_pack(const static_codebook *c,oggpack_buffer *opb){ | |||||
| long i,j; | |||||
| int ordered=0; | |||||
| /* first the basic parameters */ | |||||
| oggpack_write(opb,0x564342,24); | |||||
| oggpack_write(opb,c->dim,16); | |||||
| oggpack_write(opb,c->entries,24); | |||||
| /* pack the codewords. There are two packings; length ordered and | |||||
| length random. Decide between the two now. */ | |||||
| for(i=1;i<c->entries;i++) | |||||
| if(c->lengthlist[i-1]==0 || c->lengthlist[i]<c->lengthlist[i-1])break; | |||||
| if(i==c->entries)ordered=1; | |||||
| if(ordered){ | |||||
| /* length ordered. We only need to say how many codewords of | |||||
| each length. The actual codewords are generated | |||||
| deterministically */ | |||||
| long count=0; | |||||
| oggpack_write(opb,1,1); /* ordered */ | |||||
| oggpack_write(opb,c->lengthlist[0]-1,5); /* 1 to 32 */ | |||||
| for(i=1;i<c->entries;i++){ | |||||
| long thisx=c->lengthlist[i]; | |||||
| long last=c->lengthlist[i-1]; | |||||
| if(thisx>last){ | |||||
| for(j=last;j<thisx;j++){ | |||||
| oggpack_write(opb,i-count,_ilog(c->entries-count)); | |||||
| count=i; | |||||
| } | |||||
| } | |||||
| } | |||||
| oggpack_write(opb,i-count,_ilog(c->entries-count)); | |||||
| }else{ | |||||
| /* length random. Again, we don't code the codeword itself, just | |||||
| the length. This time, though, we have to encode each length */ | |||||
| oggpack_write(opb,0,1); /* unordered */ | |||||
| /* algortihmic mapping has use for 'unused entries', which we tag | |||||
| here. The algorithmic mapping happens as usual, but the unused | |||||
| entry has no codeword. */ | |||||
| for(i=0;i<c->entries;i++) | |||||
| if(c->lengthlist[i]==0)break; | |||||
| if(i==c->entries){ | |||||
| oggpack_write(opb,0,1); /* no unused entries */ | |||||
| for(i=0;i<c->entries;i++) | |||||
| oggpack_write(opb,c->lengthlist[i]-1,5); | |||||
| }else{ | |||||
| oggpack_write(opb,1,1); /* we have unused entries; thus we tag */ | |||||
| for(i=0;i<c->entries;i++){ | |||||
| if(c->lengthlist[i]==0){ | |||||
| oggpack_write(opb,0,1); | |||||
| }else{ | |||||
| oggpack_write(opb,1,1); | |||||
| oggpack_write(opb,c->lengthlist[i]-1,5); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| /* is the entry number the desired return value, or do we have a | |||||
| mapping? If we have a mapping, what type? */ | |||||
| oggpack_write(opb,c->maptype,4); | |||||
| switch(c->maptype){ | |||||
| case 0: | |||||
| /* no mapping */ | |||||
| break; | |||||
| case 1:case 2: | |||||
| /* implicitly populated value mapping */ | |||||
| /* explicitly populated value mapping */ | |||||
| if(!c->quantlist){ | |||||
| /* no quantlist? error */ | |||||
| return(-1); | |||||
| } | |||||
| /* values that define the dequantization */ | |||||
| oggpack_write(opb,c->q_min,32); | |||||
| oggpack_write(opb,c->q_delta,32); | |||||
| oggpack_write(opb,c->q_quant-1,4); | |||||
| oggpack_write(opb,c->q_sequencep,1); | |||||
| { | |||||
| int quantvals; | |||||
| switch(c->maptype){ | |||||
| case 1: | |||||
| /* a single column of (c->entries/c->dim) quantized values for | |||||
| building a full value list algorithmically (square lattice) */ | |||||
| quantvals=_book_maptype1_quantvals(c); | |||||
| break; | |||||
| case 2: | |||||
| /* every value (c->entries*c->dim total) specified explicitly */ | |||||
| quantvals=c->entries*c->dim; | |||||
| break; | |||||
| default: /* NOT_REACHABLE */ | |||||
| quantvals=-1; | |||||
| } | |||||
| /* quantized values */ | |||||
| for(i=0;i<quantvals;i++) | |||||
| oggpack_write(opb,labs(c->quantlist[i]),c->q_quant); | |||||
| } | |||||
| break; | |||||
| default: | |||||
| /* error case; we don't have any other map types now */ | |||||
| return(-1); | |||||
| } | |||||
| return(0); | |||||
| } | |||||
| /* unpacks a codebook from the packet buffer into the codebook struct, | |||||
| readies the codebook auxiliary structures for decode *************/ | |||||
| int vorbis_staticbook_unpack(oggpack_buffer *opb,static_codebook *s){ | |||||
| long i,j; | |||||
| memset(s,0,sizeof(*s)); | |||||
| s->allocedp=1; | |||||
| /* make sure alignment is correct */ | |||||
| if(oggpack_read(opb,24)!=0x564342)goto _eofout; | |||||
| /* first the basic parameters */ | |||||
| s->dim=oggpack_read(opb,16); | |||||
| s->entries=oggpack_read(opb,24); | |||||
| if(s->entries==-1)goto _eofout; | |||||
| /* codeword ordering.... length ordered or unordered? */ | |||||
| switch((int)oggpack_read(opb,1)){ | |||||
| case 0: | |||||
| /* unordered */ | |||||
| s->lengthlist=(long*)_ogg_malloc(sizeof(*s->lengthlist)*s->entries); | |||||
| /* allocated but unused entries? */ | |||||
| if(oggpack_read(opb,1)){ | |||||
| /* yes, unused entries */ | |||||
| for(i=0;i<s->entries;i++){ | |||||
| if(oggpack_read(opb,1)){ | |||||
| long num=oggpack_read(opb,5); | |||||
| if(num==-1)goto _eofout; | |||||
| s->lengthlist[i]=num+1; | |||||
| }else | |||||
| s->lengthlist[i]=0; | |||||
| } | |||||
| }else{ | |||||
| /* all entries used; no tagging */ | |||||
| for(i=0;i<s->entries;i++){ | |||||
| long num=oggpack_read(opb,5); | |||||
| if(num==-1)goto _eofout; | |||||
| s->lengthlist[i]=num+1; | |||||
| } | |||||
| } | |||||
| break; | |||||
| case 1: | |||||
| /* ordered */ | |||||
| { | |||||
| long length=oggpack_read(opb,5)+1; | |||||
| s->lengthlist=(long*)_ogg_malloc(sizeof(*s->lengthlist)*s->entries); | |||||
| for(i=0;i<s->entries;){ | |||||
| long num=oggpack_read(opb,_ilog(s->entries-i)); | |||||
| if(num==-1)goto _eofout; | |||||
| for(j=0;j<num && i<s->entries;j++,i++) | |||||
| s->lengthlist[i]=length; | |||||
| length++; | |||||
| } | |||||
| } | |||||
| break; | |||||
| default: | |||||
| /* EOF */ | |||||
| return(-1); | |||||
| } | |||||
| /* Do we have a mapping to unpack? */ | |||||
| switch((s->maptype=oggpack_read(opb,4))){ | |||||
| case 0: | |||||
| /* no mapping */ | |||||
| break; | |||||
| case 1: case 2: | |||||
| /* implicitly populated value mapping */ | |||||
| /* explicitly populated value mapping */ | |||||
| s->q_min=oggpack_read(opb,32); | |||||
| s->q_delta=oggpack_read(opb,32); | |||||
| s->q_quant=oggpack_read(opb,4)+1; | |||||
| s->q_sequencep=oggpack_read(opb,1); | |||||
| { | |||||
| int quantvals=0; | |||||
| switch(s->maptype){ | |||||
| case 1: | |||||
| quantvals=_book_maptype1_quantvals(s); | |||||
| break; | |||||
| case 2: | |||||
| quantvals=s->entries*s->dim; | |||||
| break; | |||||
| } | |||||
| /* quantized values */ | |||||
| s->quantlist=(long*)_ogg_malloc(sizeof(*s->quantlist)*quantvals); | |||||
| for(i=0;i<quantvals;i++) | |||||
| s->quantlist[i]=oggpack_read(opb,s->q_quant); | |||||
| if(quantvals&&s->quantlist[quantvals-1]==-1)goto _eofout; | |||||
| } | |||||
| break; | |||||
| default: | |||||
| goto _errout; | |||||
| } | |||||
| /* all set */ | |||||
| return(0); | |||||
| _errout: | |||||
| _eofout: | |||||
| vorbis_staticbook_clear(s); | |||||
| return(-1); | |||||
| } | |||||
| /* returns the number of bits ************************************************/ | |||||
| int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b){ | |||||
| oggpack_write(b,book->codelist[a],book->c->lengthlist[a]); | |||||
| return(book->c->lengthlist[a]); | |||||
| } | |||||
| /* One the encode side, our vector writers are each designed for a | |||||
| specific purpose, and the encoder is not flexible without modification: | |||||
| The LSP vector coder uses a single stage nearest-match with no | |||||
| interleave, so no step and no error return. This is specced by floor0 | |||||
| and doesn't change. | |||||
| Residue0 encoding interleaves, uses multiple stages, and each stage | |||||
| peels of a specific amount of resolution from a lattice (thus we want | |||||
| to match by threshold, not nearest match). Residue doesn't *have* to | |||||
| be encoded that way, but to change it, one will need to add more | |||||
| infrastructure on the encode side (decode side is specced and simpler) */ | |||||
| /* floor0 LSP (single stage, non interleaved, nearest match) */ | |||||
| /* returns entry number and *modifies a* to the quantization value *****/ | |||||
| int vorbis_book_errorv(codebook *book,float *a){ | |||||
| int dim=book->dim,k; | |||||
| int best=_best(book,a,1); | |||||
| for(k=0;k<dim;k++) | |||||
| a[k]=(book->valuelist+best*dim)[k]; | |||||
| return(best); | |||||
| } | |||||
| /* returns the number of bits and *modifies a* to the quantization value *****/ | |||||
| int vorbis_book_encodev(codebook *book,int best,float *a,oggpack_buffer *b){ | |||||
| int k,dim=book->dim; | |||||
| for(k=0;k<dim;k++) | |||||
| a[k]=(book->valuelist+best*dim)[k]; | |||||
| return(vorbis_book_encode(book,best,b)); | |||||
| } | |||||
| /* the 'eliminate the decode tree' optimization actually requires the | |||||
| codewords to be MSb first, not LSb. This is an annoying inelegancy | |||||
| (and one of the first places where carefully thought out design | |||||
| turned out to be wrong; Vorbis II and future Ogg codecs should go | |||||
| to an MSb bitpacker), but not actually the huge hit it appears to | |||||
| be. The first-stage decode table catches most words so that | |||||
| bitreverse is not in the main execution path. */ | |||||
| STIN long decode_packed_entry_number(codebook *book, oggpack_buffer *b){ | |||||
| int read=book->dec_maxlength; | |||||
| long lo,hi; | |||||
| long lok = oggpack_look(b,book->dec_firsttablen); | |||||
| if (lok >= 0) { | |||||
| long entry = book->dec_firsttable[lok]; | |||||
| if(entry&0x80000000UL){ | |||||
| lo=(entry>>15)&0x7fff; | |||||
| hi=book->used_entries-(entry&0x7fff); | |||||
| }else{ | |||||
| oggpack_adv(b, book->dec_codelengths[entry-1]); | |||||
| return(entry-1); | |||||
| } | |||||
| }else{ | |||||
| lo=0; | |||||
| hi=book->used_entries; | |||||
| } | |||||
| lok = oggpack_look(b, read); | |||||
| while(lok<0 && read>1) | |||||
| lok = oggpack_look(b, --read); | |||||
| if(lok<0)return -1; | |||||
| /* bisect search for the codeword in the ordered list */ | |||||
| { | |||||
| ogg_uint32_t testword=ogg_bitreverse((ogg_uint32_t)lok); | |||||
| while(hi-lo>1){ | |||||
| long p=(hi-lo)>>1; | |||||
| long test=book->codelist[lo+p]>testword; | |||||
| lo+=p&(test-1); | |||||
| hi-=p&(-test); | |||||
| } | |||||
| if(book->dec_codelengths[lo]<=read){ | |||||
| oggpack_adv(b, book->dec_codelengths[lo]); | |||||
| return(lo); | |||||
| } | |||||
| } | |||||
| oggpack_adv(b, read); | |||||
| return(-1); | |||||
| } | |||||
| /* Decode side is specced and easier, because we don't need to find | |||||
| matches using different criteria; we simply read and map. There are | |||||
| two things we need to do 'depending': | |||||
| We may need to support interleave. We don't really, but it's | |||||
| convenient to do it here rather than rebuild the vector later. | |||||
| Cascades may be additive or multiplicitive; this is not inherent in | |||||
| the codebook, but set in the code using the codebook. Like | |||||
| interleaving, it's easiest to do it here. | |||||
| addmul==0 -> declarative (set the value) | |||||
| addmul==1 -> additive | |||||
| addmul==2 -> multiplicitive */ | |||||
| /* returns the [original, not compacted] entry number or -1 on eof *********/ | |||||
| long vorbis_book_decode(codebook *book, oggpack_buffer *b){ | |||||
| long packed_entry=decode_packed_entry_number(book,b); | |||||
| if(packed_entry>=0) | |||||
| return(book->dec_index[packed_entry]); | |||||
| /* if there's no dec_index, the codebook unpacking isn't collapsed */ | |||||
| return(packed_entry); | |||||
| } | |||||
| /* returns 0 on OK or -1 on eof *************************************/ | |||||
| long vorbis_book_decodevs_add(codebook *book,float *a,oggpack_buffer *b,int n){ | |||||
| int step=n/book->dim; | |||||
| long *entry = (long*)alloca(sizeof(*entry)*step); | |||||
| float **t = (float**)alloca(sizeof(*t)*step); | |||||
| int i,j,o; | |||||
| for (i = 0; i < step; i++) { | |||||
| entry[i]=decode_packed_entry_number(book,b); | |||||
| if(entry[i]==-1)return(-1); | |||||
| t[i] = book->valuelist+entry[i]*book->dim; | |||||
| } | |||||
| for(i=0,o=0;i<book->dim;i++,o+=step) | |||||
| for (j=0;j<step;j++) | |||||
| a[o+j]+=t[j][i]; | |||||
| return(0); | |||||
| } | |||||
| long vorbis_book_decodev_add(codebook *book,float *a,oggpack_buffer *b,int n){ | |||||
| int i,j,entry; | |||||
| float *t; | |||||
| if(book->dim>8){ | |||||
| for(i=0;i<n;){ | |||||
| entry = decode_packed_entry_number(book,b); | |||||
| if(entry==-1)return(-1); | |||||
| t = book->valuelist+entry*book->dim; | |||||
| for (j=0;j<book->dim;) | |||||
| a[i++]+=t[j++]; | |||||
| } | |||||
| }else{ | |||||
| for(i=0;i<n;){ | |||||
| entry = decode_packed_entry_number(book,b); | |||||
| if(entry==-1)return(-1); | |||||
| t = book->valuelist+entry*book->dim; | |||||
| j=0; | |||||
| switch((int)book->dim){ | |||||
| case 8: | |||||
| a[i++]+=t[j++]; | |||||
| case 7: | |||||
| a[i++]+=t[j++]; | |||||
| case 6: | |||||
| a[i++]+=t[j++]; | |||||
| case 5: | |||||
| a[i++]+=t[j++]; | |||||
| case 4: | |||||
| a[i++]+=t[j++]; | |||||
| case 3: | |||||
| a[i++]+=t[j++]; | |||||
| case 2: | |||||
| a[i++]+=t[j++]; | |||||
| case 1: | |||||
| a[i++]+=t[j++]; | |||||
| case 0: | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| return(0); | |||||
| } | |||||
| long vorbis_book_decodev_set(codebook *book,float *a,oggpack_buffer *b,int n){ | |||||
| int i,j,entry; | |||||
| float *t; | |||||
| for(i=0;i<n;){ | |||||
| entry = decode_packed_entry_number(book,b); | |||||
| if(entry==-1)return(-1); | |||||
| t = book->valuelist+entry*book->dim; | |||||
| for (j=0;j<book->dim;) | |||||
| a[i++]=t[j++]; | |||||
| } | |||||
| return(0); | |||||
| } | |||||
| long vorbis_book_decodevv_add(codebook *book,float **a,long offset,int ch, | |||||
| oggpack_buffer *b,int n){ | |||||
| long i,j,entry; | |||||
| int chptr=0; | |||||
| for(i=offset/ch;i<(offset+n)/ch;){ | |||||
| entry = decode_packed_entry_number(book,b); | |||||
| if(entry==-1)return(-1); | |||||
| { | |||||
| const float *t = book->valuelist+entry*book->dim; | |||||
| for (j=0;j<book->dim;j++){ | |||||
| a[chptr++][i]+=t[j]; | |||||
| if(chptr==ch){ | |||||
| chptr=0; | |||||
| i++; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| return(0); | |||||
| } | |||||
| #ifdef _V_SELFTEST | |||||
| /* Simple enough; pack a few candidate codebooks, unpack them. Code a | |||||
| number of vectors through (keeping track of the quantized values), | |||||
| and decode using the unpacked book. quantized version of in should | |||||
| exactly equal out */ | |||||
| #include <stdio.h> | |||||
| #include "vorbis/book/lsp20_0.vqh" | |||||
| #include "vorbis/book/res0a_13.vqh" | |||||
| #define TESTSIZE 40 | |||||
| float test1[TESTSIZE]={ | |||||
| 0.105939f, | |||||
| 0.215373f, | |||||
| 0.429117f, | |||||
| 0.587974f, | |||||
| 0.181173f, | |||||
| 0.296583f, | |||||
| 0.515707f, | |||||
| 0.715261f, | |||||
| 0.162327f, | |||||
| 0.263834f, | |||||
| 0.342876f, | |||||
| 0.406025f, | |||||
| 0.103571f, | |||||
| 0.223561f, | |||||
| 0.368513f, | |||||
| 0.540313f, | |||||
| 0.136672f, | |||||
| 0.395882f, | |||||
| 0.587183f, | |||||
| 0.652476f, | |||||
| 0.114338f, | |||||
| 0.417300f, | |||||
| 0.525486f, | |||||
| 0.698679f, | |||||
| 0.147492f, | |||||
| 0.324481f, | |||||
| 0.643089f, | |||||
| 0.757582f, | |||||
| 0.139556f, | |||||
| 0.215795f, | |||||
| 0.324559f, | |||||
| 0.399387f, | |||||
| 0.120236f, | |||||
| 0.267420f, | |||||
| 0.446940f, | |||||
| 0.608760f, | |||||
| 0.115587f, | |||||
| 0.287234f, | |||||
| 0.571081f, | |||||
| 0.708603f, | |||||
| }; | |||||
| float test3[TESTSIZE]={ | |||||
| 0,1,-2,3,4,-5,6,7,8,9, | |||||
| 8,-2,7,-1,4,6,8,3,1,-9, | |||||
| 10,11,12,13,14,15,26,17,18,19, | |||||
| 30,-25,-30,-1,-5,-32,4,3,-2,0}; | |||||
| static_codebook *testlist[]={&_vq_book_lsp20_0, | |||||
| &_vq_book_res0a_13,NULL}; | |||||
| float *testvec[]={test1,test3}; | |||||
| int main(){ | |||||
| oggpack_buffer write; | |||||
| oggpack_buffer read; | |||||
| long ptr=0,i; | |||||
| oggpack_writeinit(&write); | |||||
| fprintf(stderr,"Testing codebook abstraction...:\n"); | |||||
| while(testlist[ptr]){ | |||||
| codebook c; | |||||
| static_codebook s; | |||||
| float *qv=alloca(sizeof(*qv)*TESTSIZE); | |||||
| float *iv=alloca(sizeof(*iv)*TESTSIZE); | |||||
| memcpy(qv,testvec[ptr],sizeof(*qv)*TESTSIZE); | |||||
| memset(iv,0,sizeof(*iv)*TESTSIZE); | |||||
| fprintf(stderr,"\tpacking/coding %ld... ",ptr); | |||||
| /* pack the codebook, write the testvector */ | |||||
| oggpack_reset(&write); | |||||
| vorbis_book_init_encode(&c,testlist[ptr]); /* get it into memory | |||||
| we can write */ | |||||
| vorbis_staticbook_pack(testlist[ptr],&write); | |||||
| fprintf(stderr,"Codebook size %ld bytes... ",oggpack_bytes(&write)); | |||||
| for(i=0;i<TESTSIZE;i+=c.dim){ | |||||
| int best=_best(&c,qv+i,1); | |||||
| vorbis_book_encodev(&c,best,qv+i,&write); | |||||
| } | |||||
| vorbis_book_clear(&c); | |||||
| fprintf(stderr,"OK.\n"); | |||||
| fprintf(stderr,"\tunpacking/decoding %ld... ",ptr); | |||||
| /* transfer the write data to a read buffer and unpack/read */ | |||||
| oggpack_readinit(&read,oggpack_get_buffer(&write),oggpack_bytes(&write)); | |||||
| if(vorbis_staticbook_unpack(&read,&s)){ | |||||
| fprintf(stderr,"Error unpacking codebook.\n"); | |||||
| exit(1); | |||||
| } | |||||
| if(vorbis_book_init_decode(&c,&s)){ | |||||
| fprintf(stderr,"Error initializing codebook.\n"); | |||||
| exit(1); | |||||
| } | |||||
| for(i=0;i<TESTSIZE;i+=c.dim) | |||||
| if(vorbis_book_decodev_set(&c,iv+i,&read,c.dim)==-1){ | |||||
| fprintf(stderr,"Error reading codebook test data (EOP).\n"); | |||||
| exit(1); | |||||
| } | |||||
| for(i=0;i<TESTSIZE;i++) | |||||
| if(fabs(qv[i]-iv[i])>.000001){ | |||||
| fprintf(stderr,"read (%g) != written (%g) at position (%ld)\n", | |||||
| iv[i],qv[i],i); | |||||
| exit(1); | |||||
| } | |||||
| fprintf(stderr,"OK\n"); | |||||
| ptr++; | |||||
| } | |||||
| /* The above is the trivial stuff; now try unquantizing a log scale codebook */ | |||||
| exit(0); | |||||
| } | |||||
| #endif | |||||
| #endif | |||||
| @@ -0,0 +1,160 @@ | |||||
| /******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * | |||||
| * by the XIPHOPHORUS Company http://www.xiph.org/ * | |||||
| * * | |||||
| ******************************************************************** | |||||
| function: basic shared codebook operations | |||||
| last mod: $Id: codebook.h,v 1.1 2007/06/07 17:49:17 jules_rms Exp $ | |||||
| ********************************************************************/ | |||||
| #ifndef _V_CODEBOOK_H_ | |||||
| #define _V_CODEBOOK_H_ | |||||
| #include "../../ogg.h" | |||||
| /* This structure encapsulates huffman and VQ style encoding books; it | |||||
| doesn't do anything specific to either. | |||||
| valuelist/quantlist are nonNULL (and q_* significant) only if | |||||
| there's entry->value mapping to be done. | |||||
| If encode-side mapping must be done (and thus the entry needs to be | |||||
| hunted), the auxiliary encode pointer will point to a decision | |||||
| tree. This is true of both VQ and huffman, but is mostly useful | |||||
| with VQ. | |||||
| */ | |||||
| typedef struct static_codebook{ | |||||
| long dim; /* codebook dimensions (elements per vector) */ | |||||
| long entries; /* codebook entries */ | |||||
| long *lengthlist; /* codeword lengths in bits */ | |||||
| /* mapping ***************************************************************/ | |||||
| int maptype; /* 0=none | |||||
| 1=implicitly populated values from map column | |||||
| 2=listed arbitrary values */ | |||||
| /* The below does a linear, single monotonic sequence mapping. */ | |||||
| long q_min; /* packed 32 bit float; quant value 0 maps to minval */ | |||||
| long q_delta; /* packed 32 bit float; val 1 - val 0 == delta */ | |||||
| int q_quant; /* bits: 0 < quant <= 16 */ | |||||
| int q_sequencep; /* bitflag */ | |||||
| long *quantlist; /* map == 1: (int)(entries^(1/dim)) element column map | |||||
| map == 2: list of dim*entries quantized entry vals | |||||
| */ | |||||
| /* encode helpers ********************************************************/ | |||||
| struct encode_aux_nearestmatch *nearest_tree; | |||||
| struct encode_aux_threshmatch *thresh_tree; | |||||
| struct encode_aux_pigeonhole *pigeon_tree; | |||||
| int allocedp; | |||||
| } static_codebook; | |||||
| /* this structures an arbitrary trained book to quickly find the | |||||
| nearest cell match */ | |||||
| typedef struct encode_aux_nearestmatch{ | |||||
| /* pre-calculated partitioning tree */ | |||||
| long *ptr0; | |||||
| long *ptr1; | |||||
| long *p; /* decision points (each is an entry) */ | |||||
| long *q; /* decision points (each is an entry) */ | |||||
| long aux; /* number of tree entries */ | |||||
| long alloc; | |||||
| } encode_aux_nearestmatch; | |||||
| /* assumes a maptype of 1; encode side only, so that's OK */ | |||||
| typedef struct encode_aux_threshmatch{ | |||||
| float *quantthresh; | |||||
| long *quantmap; | |||||
| int quantvals; | |||||
| int threshvals; | |||||
| } encode_aux_threshmatch; | |||||
| typedef struct encode_aux_pigeonhole{ | |||||
| float min; | |||||
| float del; | |||||
| int mapentries; | |||||
| int quantvals; | |||||
| long *pigeonmap; | |||||
| long fittotal; | |||||
| long *fitlist; | |||||
| long *fitmap; | |||||
| long *fitlength; | |||||
| } encode_aux_pigeonhole; | |||||
| typedef struct codebook{ | |||||
| long dim; /* codebook dimensions (elements per vector) */ | |||||
| long entries; /* codebook entries */ | |||||
| long used_entries; /* populated codebook entries */ | |||||
| const static_codebook *c; | |||||
| /* for encode, the below are entry-ordered, fully populated */ | |||||
| /* for decode, the below are ordered by bitreversed codeword and only | |||||
| used entries are populated */ | |||||
| float *valuelist; /* list of dim*entries actual entry values */ | |||||
| ogg_uint32_t *codelist; /* list of bitstream codewords for each entry */ | |||||
| int *dec_index; /* only used if sparseness collapsed */ | |||||
| char *dec_codelengths; | |||||
| ogg_uint32_t *dec_firsttable; | |||||
| int dec_firsttablen; | |||||
| int dec_maxlength; | |||||
| } codebook; | |||||
| extern void vorbis_staticbook_clear(static_codebook *b); | |||||
| extern void vorbis_staticbook_destroy(static_codebook *b); | |||||
| extern int vorbis_book_init_encode(codebook *dest,const static_codebook *source); | |||||
| extern int vorbis_book_init_decode(codebook *dest,const static_codebook *source); | |||||
| extern void vorbis_book_clear(codebook *b); | |||||
| extern float *_book_unquantize(const static_codebook *b,int n,int *map); | |||||
| extern float *_book_logdist(const static_codebook *b,float *vals); | |||||
| extern float _float32_unpack(long val); | |||||
| extern long _float32_pack(float val); | |||||
| extern int _best(codebook *book, float *a, int step); | |||||
| extern int _ilog(unsigned int v); | |||||
| extern long _book_maptype1_quantvals(const static_codebook *b); | |||||
| extern int vorbis_book_besterror(codebook *book,float *a,int step,int addmul); | |||||
| extern long vorbis_book_codeword(codebook *book,int entry); | |||||
| extern long vorbis_book_codelen(codebook *book,int entry); | |||||
| extern int vorbis_staticbook_pack(const static_codebook *c,oggpack_buffer *b); | |||||
| extern int vorbis_staticbook_unpack(oggpack_buffer *b,static_codebook *c); | |||||
| extern int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b); | |||||
| extern int vorbis_book_errorv(codebook *book, float *a); | |||||
| extern int vorbis_book_encodev(codebook *book, int best,float *a, | |||||
| oggpack_buffer *b); | |||||
| extern long vorbis_book_decode(codebook *book, oggpack_buffer *b); | |||||
| extern long vorbis_book_decodevs_add(codebook *book, float *a, | |||||
| oggpack_buffer *b,int n); | |||||
| extern long vorbis_book_decodev_set(codebook *book, float *a, | |||||
| oggpack_buffer *b,int n); | |||||
| extern long vorbis_book_decodev_add(codebook *book, float *a, | |||||
| oggpack_buffer *b,int n); | |||||
| extern long vorbis_book_decodevv_add(codebook *book, float **a, | |||||
| long off,int ch, | |||||
| oggpack_buffer *b,int n); | |||||
| #endif | |||||
| @@ -0,0 +1,156 @@ | |||||
| /******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * | |||||
| * by the XIPHOPHORUS Company http://www.xiph.org/ * | |||||
| * * | |||||
| ******************************************************************** | |||||
| function: libvorbis codec headers | |||||
| last mod: $Id: codec_internal.h,v 1.1 2007/06/07 17:49:17 jules_rms Exp $ | |||||
| ********************************************************************/ | |||||
| #ifndef _V_CODECI_H_ | |||||
| #define _V_CODECI_H_ | |||||
| #include "envelope.h" | |||||
| #include "codebook.h" | |||||
| #define BLOCKTYPE_IMPULSE 0 | |||||
| #define BLOCKTYPE_PADDING 1 | |||||
| #define BLOCKTYPE_TRANSITION 0 | |||||
| #define BLOCKTYPE_LONG 1 | |||||
| #define PACKETBLOBS 15 | |||||
| typedef struct vorbis_block_internal{ | |||||
| float **pcmdelay; /* this is a pointer into local storage */ | |||||
| float ampmax; | |||||
| int blocktype; | |||||
| oggpack_buffer *packetblob[PACKETBLOBS]; /* initialized, must be freed; | |||||
| blob [PACKETBLOBS/2] points to | |||||
| the oggpack_buffer in the | |||||
| main vorbis_block */ | |||||
| } vorbis_block_internal; | |||||
| typedef void vorbis_look_floor; | |||||
| typedef void vorbis_look_residue; | |||||
| typedef void vorbis_look_transform; | |||||
| /* mode ************************************************************/ | |||||
| typedef struct { | |||||
| int blockflag; | |||||
| int windowtype; | |||||
| int transformtype; | |||||
| int mapping; | |||||
| } vorbis_info_mode; | |||||
| typedef void vorbis_info_floor; | |||||
| typedef void vorbis_info_residue; | |||||
| typedef void vorbis_info_mapping; | |||||
| #include "psy.h" | |||||
| #include "bitrate.h" | |||||
| static int ilog(unsigned int v){ | |||||
| int ret=0; | |||||
| while(v){ | |||||
| ret++; | |||||
| v>>=1; | |||||
| } | |||||
| return(ret); | |||||
| } | |||||
| static int ilog2(unsigned int v){ | |||||
| int ret=0; | |||||
| if(v)--v; | |||||
| while(v){ | |||||
| ret++; | |||||
| v>>=1; | |||||
| } | |||||
| return(ret); | |||||
| } | |||||
| typedef struct private_state { | |||||
| /* local lookup storage */ | |||||
| envelope_lookup *ve; /* envelope lookup */ | |||||
| int window[2]; | |||||
| vorbis_look_transform **transform[2]; /* block, type */ | |||||
| drft_lookup fft_look[2]; | |||||
| int modebits; | |||||
| vorbis_look_floor **flr; | |||||
| vorbis_look_residue **residue; | |||||
| vorbis_look_psy *psy; | |||||
| vorbis_look_psy_global *psy_g_look; | |||||
| /* local storage, only used on the encoding side. This way the | |||||
| application does not need to worry about freeing some packets' | |||||
| memory and not others'; packet storage is always tracked. | |||||
| Cleared next call to a _dsp_ function */ | |||||
| unsigned char *header; | |||||
| unsigned char *header1; | |||||
| unsigned char *header2; | |||||
| bitrate_manager_state bms; | |||||
| ogg_int64_t sample_count; | |||||
| } private_state; | |||||
| /* codec_setup_info contains all the setup information specific to the | |||||
| specific compression/decompression mode in progress (eg, | |||||
| psychoacoustic settings, channel setup, options, codebook | |||||
| etc). | |||||
| *********************************************************************/ | |||||
| #include "highlevel.h" | |||||
| typedef struct codec_setup_info { | |||||
| /* Vorbis supports only short and long blocks, but allows the | |||||
| encoder to choose the sizes */ | |||||
| long blocksizes[2]; | |||||
| /* modes are the primary means of supporting on-the-fly different | |||||
| blocksizes, different channel mappings (LR or M/A), | |||||
| different residue backends, etc. Each mode consists of a | |||||
| blocksize flag and a mapping (along with the mapping setup */ | |||||
| int modes; | |||||
| int maps; | |||||
| int floors; | |||||
| int residues; | |||||
| int books; | |||||
| int psys; /* encode only */ | |||||
| vorbis_info_mode *mode_param[64]; | |||||
| int map_type[64]; | |||||
| vorbis_info_mapping *map_param[64]; | |||||
| int floor_type[64]; | |||||
| vorbis_info_floor *floor_param[64]; | |||||
| int residue_type[64]; | |||||
| vorbis_info_residue *residue_param[64]; | |||||
| static_codebook *book_param[256]; | |||||
| codebook *fullbooks; | |||||
| vorbis_info_psy *psy_param[4]; /* encode only */ | |||||
| vorbis_info_psy_global psy_g_param; | |||||
| bitrate_manager_info bi; | |||||
| highlevel_encode_setup hi; /* used only by vorbisenc.c. It's a | |||||
| highly redundant structure, but | |||||
| improves clarity of program flow. */ | |||||
| int halfrate_flag; /* painless downsample for decode */ | |||||
| } codec_setup_info; | |||||
| extern vorbis_look_psy_global *_vp_global_look(vorbis_info *vi); | |||||
| extern void _vp_global_free(vorbis_look_psy_global *look); | |||||
| #endif | |||||
| @@ -0,0 +1,383 @@ | |||||
| /******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * | |||||
| * by the XIPHOPHORUS Company http://www.xiph.org/ * | |||||
| * * | |||||
| ******************************************************************** | |||||
| function: PCM data envelope analysis | |||||
| last mod: $Id: envelope.c,v 1.1 2007/06/07 17:49:17 jules_rms Exp $ | |||||
| ********************************************************************/ | |||||
| #include "../../juce_OggVorbisHeader.h" | |||||
| #if JUCE_USE_OGGVORBIS | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| #include <stdio.h> | |||||
| #include <math.h> | |||||
| #include "../../ogg.h" | |||||
| #include "../../codec.h" | |||||
| #include "codec_internal.h" | |||||
| #include "os.h" | |||||
| #include "scales.h" | |||||
| #include "envelope.h" | |||||
| #include "mdct.h" | |||||
| #include "misc.h" | |||||
| void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi){ | |||||
| codec_setup_info *ci=(codec_setup_info*)vi->codec_setup; | |||||
| vorbis_info_psy_global *gi=&ci->psy_g_param; | |||||
| int ch=vi->channels; | |||||
| int i,j; | |||||
| int n=e->winlength=128; | |||||
| e->searchstep=64; /* not random */ | |||||
| e->minenergy=gi->preecho_minenergy; | |||||
| e->ch=ch; | |||||
| e->storage=128; | |||||
| e->cursor=ci->blocksizes[1]/2; | |||||
| e->mdct_win=(float*)_ogg_calloc(n,sizeof(*e->mdct_win)); | |||||
| mdct_init(&e->mdct,n); | |||||
| for(i=0;i<n;i++){ | |||||
| e->mdct_win[i]=sin(i/(n-1.)*M_PI); | |||||
| e->mdct_win[i]*=e->mdct_win[i]; | |||||
| } | |||||
| /* magic follows */ | |||||
| e->band[0].begin=2; e->band[0].end=4; | |||||
| e->band[1].begin=4; e->band[1].end=5; | |||||
| e->band[2].begin=6; e->band[2].end=6; | |||||
| e->band[3].begin=9; e->band[3].end=8; | |||||
| e->band[4].begin=13; e->band[4].end=8; | |||||
| e->band[5].begin=17; e->band[5].end=8; | |||||
| e->band[6].begin=22; e->band[6].end=8; | |||||
| for(j=0;j<VE_BANDS;j++){ | |||||
| n=e->band[j].end; | |||||
| e->band[j].window=(float*)_ogg_malloc(n*sizeof(*e->band[0].window)); | |||||
| for(i=0;i<n;i++){ | |||||
| e->band[j].window[i]=sin((i+.5)/n*M_PI); | |||||
| e->band[j].total+=e->band[j].window[i]; | |||||
| } | |||||
| e->band[j].total=1./e->band[j].total; | |||||
| } | |||||
| e->filter=(envelope_filter_state*)_ogg_calloc(VE_BANDS*ch,sizeof(*e->filter)); | |||||
| e->mark=(int*)_ogg_calloc(e->storage,sizeof(*e->mark)); | |||||
| } | |||||
| void _ve_envelope_clear(envelope_lookup *e){ | |||||
| int i; | |||||
| mdct_clear(&e->mdct); | |||||
| for(i=0;i<VE_BANDS;i++) | |||||
| _ogg_free(e->band[i].window); | |||||
| _ogg_free(e->mdct_win); | |||||
| _ogg_free(e->filter); | |||||
| _ogg_free(e->mark); | |||||
| memset(e,0,sizeof(*e)); | |||||
| } | |||||
| /* fairly straight threshhold-by-band based until we find something | |||||
| that works better and isn't patented. */ | |||||
| static int _ve_amp(envelope_lookup *ve, | |||||
| vorbis_info_psy_global *gi, | |||||
| float *data, | |||||
| envelope_band *bands, | |||||
| envelope_filter_state *filters, | |||||
| long pos){ | |||||
| long n=ve->winlength; | |||||
| int ret=0; | |||||
| long i,j; | |||||
| float decay; | |||||
| /* we want to have a 'minimum bar' for energy, else we're just | |||||
| basing blocks on quantization noise that outweighs the signal | |||||
| itself (for low power signals) */ | |||||
| float minV=ve->minenergy; | |||||
| float *vec=(float*) alloca(n*sizeof(*vec)); | |||||
| /* stretch is used to gradually lengthen the number of windows | |||||
| considered prevoius-to-potential-trigger */ | |||||
| int stretch=max(VE_MINSTRETCH,ve->stretch/2); | |||||
| float penalty=gi->stretch_penalty-(ve->stretch/2-VE_MINSTRETCH); | |||||
| if(penalty<0.f)penalty=0.f; | |||||
| if(penalty>gi->stretch_penalty)penalty=gi->stretch_penalty; | |||||
| /*_analysis_output_always("lpcm",seq2,data,n,0,0, | |||||
| totalshift+pos*ve->searchstep);*/ | |||||
| /* window and transform */ | |||||
| for(i=0;i<n;i++) | |||||
| vec[i]=data[i]*ve->mdct_win[i]; | |||||
| mdct_forward(&ve->mdct,vec,vec); | |||||
| /*_analysis_output_always("mdct",seq2,vec,n/2,0,1,0); */ | |||||
| /* near-DC spreading function; this has nothing to do with | |||||
| psychoacoustics, just sidelobe leakage and window size */ | |||||
| { | |||||
| float temp=vec[0]*vec[0]+.7*vec[1]*vec[1]+.2*vec[2]*vec[2]; | |||||
| int ptr=filters->nearptr; | |||||
| /* the accumulation is regularly refreshed from scratch to avoid | |||||
| floating point creep */ | |||||
| if(ptr==0){ | |||||
| decay=filters->nearDC_acc=filters->nearDC_partialacc+temp; | |||||
| filters->nearDC_partialacc=temp; | |||||
| }else{ | |||||
| decay=filters->nearDC_acc+=temp; | |||||
| filters->nearDC_partialacc+=temp; | |||||
| } | |||||
| filters->nearDC_acc-=filters->nearDC[ptr]; | |||||
| filters->nearDC[ptr]=temp; | |||||
| decay*=(1./(VE_NEARDC+1)); | |||||
| filters->nearptr++; | |||||
| if(filters->nearptr>=VE_NEARDC)filters->nearptr=0; | |||||
| decay=todB(&decay)*.5-15.f; | |||||
| } | |||||
| /* perform spreading and limiting, also smooth the spectrum. yes, | |||||
| the MDCT results in all real coefficients, but it still *behaves* | |||||
| like real/imaginary pairs */ | |||||
| for(i=0;i<n/2;i+=2){ | |||||
| float val=vec[i]*vec[i]+vec[i+1]*vec[i+1]; | |||||
| val=todB(&val)*.5f; | |||||
| if(val<decay)val=decay; | |||||
| if(val<minV)val=minV; | |||||
| vec[i>>1]=val; | |||||
| decay-=8.; | |||||
| } | |||||
| /*_analysis_output_always("spread",seq2++,vec,n/4,0,0,0);*/ | |||||
| /* perform preecho/postecho triggering by band */ | |||||
| for(j=0;j<VE_BANDS;j++){ | |||||
| float acc=0.; | |||||
| float valmax,valmin; | |||||
| /* accumulate amplitude */ | |||||
| for(i=0;i<bands[j].end;i++) | |||||
| acc+=vec[i+bands[j].begin]*bands[j].window[i]; | |||||
| acc*=bands[j].total; | |||||
| /* convert amplitude to delta */ | |||||
| { | |||||
| int p,thisx=filters[j].ampptr; | |||||
| float postmax,postmin,premax=-99999.f,premin=99999.f; | |||||
| p=thisx; | |||||
| p--; | |||||
| if(p<0)p+=VE_AMP; | |||||
| postmax=max(acc,filters[j].ampbuf[p]); | |||||
| postmin=min(acc,filters[j].ampbuf[p]); | |||||
| for(i=0;i<stretch;i++){ | |||||
| p--; | |||||
| if(p<0)p+=VE_AMP; | |||||
| premax=max(premax,filters[j].ampbuf[p]); | |||||
| premin=min(premin,filters[j].ampbuf[p]); | |||||
| } | |||||
| valmin=postmin-premin; | |||||
| valmax=postmax-premax; | |||||
| /*filters[j].markers[pos]=valmax;*/ | |||||
| filters[j].ampbuf[thisx]=acc; | |||||
| filters[j].ampptr++; | |||||
| if(filters[j].ampptr>=VE_AMP)filters[j].ampptr=0; | |||||
| } | |||||
| /* look at min/max, decide trigger */ | |||||
| if(valmax>gi->preecho_thresh[j]+penalty){ | |||||
| ret|=1; | |||||
| ret|=4; | |||||
| } | |||||
| if(valmin<gi->postecho_thresh[j]-penalty)ret|=2; | |||||
| } | |||||
| return(ret); | |||||
| } | |||||
| #if 0 | |||||
| static int seq=0; | |||||
| static ogg_int64_t totalshift=-1024; | |||||
| #endif | |||||
| long _ve_envelope_search(vorbis_dsp_state *v){ | |||||
| vorbis_info *vi=v->vi; | |||||
| codec_setup_info *ci=(codec_setup_info *)vi->codec_setup; | |||||
| vorbis_info_psy_global *gi=&ci->psy_g_param; | |||||
| envelope_lookup *ve=((private_state *)(v->backend_state))->ve; | |||||
| long i,j; | |||||
| int first=ve->current/ve->searchstep; | |||||
| int last=v->pcm_current/ve->searchstep-VE_WIN; | |||||
| if(first<0)first=0; | |||||
| /* make sure we have enough storage to match the PCM */ | |||||
| if(last+VE_WIN+VE_POST>ve->storage){ | |||||
| ve->storage=last+VE_WIN+VE_POST; /* be sure */ | |||||
| ve->mark=(int*)_ogg_realloc(ve->mark,ve->storage*sizeof(*ve->mark)); | |||||
| } | |||||
| for(j=first;j<last;j++){ | |||||
| int ret=0; | |||||
| ve->stretch++; | |||||
| if(ve->stretch>VE_MAXSTRETCH*2) | |||||
| ve->stretch=VE_MAXSTRETCH*2; | |||||
| for(i=0;i<ve->ch;i++){ | |||||
| float *pcm=v->pcm[i]+ve->searchstep*(j); | |||||
| ret|=_ve_amp(ve,gi,pcm,ve->band,ve->filter+i*VE_BANDS,j); | |||||
| } | |||||
| ve->mark[j+VE_POST]=0; | |||||
| if(ret&1){ | |||||
| ve->mark[j]=1; | |||||
| ve->mark[j+1]=1; | |||||
| } | |||||
| if(ret&2){ | |||||
| ve->mark[j]=1; | |||||
| if(j>0)ve->mark[j-1]=1; | |||||
| } | |||||
| if(ret&4)ve->stretch=-1; | |||||
| } | |||||
| ve->current=last*ve->searchstep; | |||||
| { | |||||
| long centerW=v->centerW; | |||||
| long testW= | |||||
| centerW+ | |||||
| ci->blocksizes[v->W]/4+ | |||||
| ci->blocksizes[1]/2+ | |||||
| ci->blocksizes[0]/4; | |||||
| j=ve->cursor; | |||||
| while(j<ve->current-(ve->searchstep)){/* account for postecho | |||||
| working back one window */ | |||||
| if(j>=testW)return(1); | |||||
| ve->cursor=j; | |||||
| if(ve->mark[j/ve->searchstep]){ | |||||
| if(j>centerW){ | |||||
| #if 0 | |||||
| if(j>ve->curmark){ | |||||
| float *marker=alloca(v->pcm_current*sizeof(*marker)); | |||||
| int l,m; | |||||
| memset(marker,0,sizeof(*marker)*v->pcm_current); | |||||
| fprintf(stderr,"mark! seq=%d, cursor:%fs time:%fs\n", | |||||
| seq, | |||||
| (totalshift+ve->cursor)/44100., | |||||
| (totalshift+j)/44100.); | |||||
| _analysis_output_always("pcmL",seq,v->pcm[0],v->pcm_current,0,0,totalshift); | |||||
| _analysis_output_always("pcmR",seq,v->pcm[1],v->pcm_current,0,0,totalshift); | |||||
| _analysis_output_always("markL",seq,v->pcm[0],j,0,0,totalshift); | |||||
| _analysis_output_always("markR",seq,v->pcm[1],j,0,0,totalshift); | |||||
| for(m=0;m<VE_BANDS;m++){ | |||||
| char buf[80]; | |||||
| sprintf(buf,"delL%d",m); | |||||
| for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->filter[m].markers[l]*.1; | |||||
| _analysis_output_always(buf,seq,marker,v->pcm_current,0,0,totalshift); | |||||
| } | |||||
| for(m=0;m<VE_BANDS;m++){ | |||||
| char buf[80]; | |||||
| sprintf(buf,"delR%d",m); | |||||
| for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->filter[m+VE_BANDS].markers[l]*.1; | |||||
| _analysis_output_always(buf,seq,marker,v->pcm_current,0,0,totalshift); | |||||
| } | |||||
| for(l=0;l<last;l++)marker[l*ve->searchstep]=ve->mark[l]*.4; | |||||
| _analysis_output_always("mark",seq,marker,v->pcm_current,0,0,totalshift); | |||||
| seq++; | |||||
| } | |||||
| #endif | |||||
| ve->curmark=j; | |||||
| if(j>=testW)return(1); | |||||
| return(0); | |||||
| } | |||||
| } | |||||
| j+=ve->searchstep; | |||||
| } | |||||
| } | |||||
| return(-1); | |||||
| } | |||||
| int _ve_envelope_mark(vorbis_dsp_state *v){ | |||||
| envelope_lookup *ve=((private_state *)(v->backend_state))->ve; | |||||
| vorbis_info *vi=v->vi; | |||||
| codec_setup_info *ci=(codec_setup_info*)vi->codec_setup; | |||||
| long centerW=v->centerW; | |||||
| long beginW=centerW-ci->blocksizes[v->W]/4; | |||||
| long endW=centerW+ci->blocksizes[v->W]/4; | |||||
| if(v->W){ | |||||
| beginW-=ci->blocksizes[v->lW]/4; | |||||
| endW+=ci->blocksizes[v->nW]/4; | |||||
| }else{ | |||||
| beginW-=ci->blocksizes[0]/4; | |||||
| endW+=ci->blocksizes[0]/4; | |||||
| } | |||||
| if(ve->curmark>=beginW && ve->curmark<endW)return(1); | |||||
| { | |||||
| long first=beginW/ve->searchstep; | |||||
| long last=endW/ve->searchstep; | |||||
| long i; | |||||
| for(i=first;i<last;i++) | |||||
| if(ve->mark[i])return(1); | |||||
| } | |||||
| return(0); | |||||
| } | |||||
| void _ve_envelope_shift(envelope_lookup *e,long shift){ | |||||
| int smallsize=e->current/e->searchstep+VE_POST; /* adjust for placing marks | |||||
| ahead of ve->current */ | |||||
| int smallshift=shift/e->searchstep; | |||||
| memmove(e->mark,e->mark+smallshift,(smallsize-smallshift)*sizeof(*e->mark)); | |||||
| #if 0 | |||||
| for(i=0;i<VE_BANDS*e->ch;i++) | |||||
| memmove(e->filter[i].markers, | |||||
| e->filter[i].markers+smallshift, | |||||
| (1024-smallshift)*sizeof(*(*e->filter).markers)); | |||||
| totalshift+=shift; | |||||
| #endif | |||||
| e->current-=shift; | |||||
| if(e->curmark>=0) | |||||
| e->curmark-=shift; | |||||
| e->cursor-=shift; | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,80 @@ | |||||
| /******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * | |||||
| * by the XIPHOPHORUS Company http://www.xiph.org/ * | |||||
| * * | |||||
| ******************************************************************** | |||||
| function: PCM data envelope analysis and manipulation | |||||
| last mod: $Id: envelope.h,v 1.1 2007/06/07 17:49:17 jules_rms Exp $ | |||||
| ********************************************************************/ | |||||
| #ifndef _V_ENVELOPE_ | |||||
| #define _V_ENVELOPE_ | |||||
| #include "mdct.h" | |||||
| #define VE_PRE 16 | |||||
| #define VE_WIN 4 | |||||
| #define VE_POST 2 | |||||
| #define VE_AMP (VE_PRE+VE_POST-1) | |||||
| #define VE_BANDS 7 | |||||
| #define VE_NEARDC 15 | |||||
| #define VE_MINSTRETCH 2 /* a bit less than short block */ | |||||
| #define VE_MAXSTRETCH 12 /* one-third full block */ | |||||
| typedef struct { | |||||
| float ampbuf[VE_AMP]; | |||||
| int ampptr; | |||||
| float nearDC[VE_NEARDC]; | |||||
| float nearDC_acc; | |||||
| float nearDC_partialacc; | |||||
| int nearptr; | |||||
| } envelope_filter_state; | |||||
| typedef struct { | |||||
| int begin; | |||||
| int end; | |||||
| float *window; | |||||
| float total; | |||||
| } envelope_band; | |||||
| typedef struct { | |||||
| int ch; | |||||
| int winlength; | |||||
| int searchstep; | |||||
| float minenergy; | |||||
| mdct_lookup mdct; | |||||
| float *mdct_win; | |||||
| envelope_band band[VE_BANDS]; | |||||
| envelope_filter_state *filter; | |||||
| int stretch; | |||||
| int *mark; | |||||
| long storage; | |||||
| long current; | |||||
| long curmark; | |||||
| long cursor; | |||||
| } envelope_lookup; | |||||
| extern void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi); | |||||
| extern void _ve_envelope_clear(envelope_lookup *e); | |||||
| extern long _ve_envelope_search(vorbis_dsp_state *v); | |||||
| extern void _ve_envelope_shift(envelope_lookup *e,long shift); | |||||
| extern int _ve_envelope_mark(vorbis_dsp_state *v); | |||||
| #endif | |||||
| @@ -0,0 +1,227 @@ | |||||
| /******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * | |||||
| * by the XIPHOPHORUS Company http://www.xiph.org/ * | |||||
| * * | |||||
| ******************************************************************** | |||||
| function: floor backend 0 implementation | |||||
| last mod: $Id: floor0.c,v 1.1 2007/06/07 17:49:17 jules_rms Exp $ | |||||
| ********************************************************************/ | |||||
| #include "../../juce_OggVorbisHeader.h" | |||||
| #if JUCE_USE_OGGVORBIS | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| #include <math.h> | |||||
| #include "../../ogg.h" | |||||
| #include "../../codec.h" | |||||
| #include "codec_internal.h" | |||||
| #include "registry.h" | |||||
| #include "lpc.h" | |||||
| #include "lsp.h" | |||||
| #include "codebook.h" | |||||
| #include "scales.h" | |||||
| #include "misc.h" | |||||
| #include "os.h" | |||||
| #include "misc.h" | |||||
| #include <stdio.h> | |||||
| typedef struct { | |||||
| int ln; | |||||
| int m; | |||||
| int **linearmap; | |||||
| int n[2]; | |||||
| vorbis_info_floor0 *vi; | |||||
| long bits; | |||||
| long frames; | |||||
| } vorbis_look_floor0; | |||||
| /***********************************************/ | |||||
| static void floor0_free_info(vorbis_info_floor *i){ | |||||
| vorbis_info_floor0 *info=(vorbis_info_floor0 *)i; | |||||
| if(info){ | |||||
| memset(info,0,sizeof(*info)); | |||||
| _ogg_free(info); | |||||
| } | |||||
| } | |||||
| static void floor0_free_look(vorbis_look_floor *i){ | |||||
| vorbis_look_floor0 *look=(vorbis_look_floor0 *)i; | |||||
| if(look){ | |||||
| if(look->linearmap){ | |||||
| if(look->linearmap[0])_ogg_free(look->linearmap[0]); | |||||
| if(look->linearmap[1])_ogg_free(look->linearmap[1]); | |||||
| _ogg_free(look->linearmap); | |||||
| } | |||||
| memset(look,0,sizeof(*look)); | |||||
| _ogg_free(look); | |||||
| } | |||||
| } | |||||
| static vorbis_info_floor *floor0_unpack (vorbis_info *vi,oggpack_buffer *opb){ | |||||
| codec_setup_info *ci=(codec_setup_info*)vi->codec_setup; | |||||
| int j; | |||||
| vorbis_info_floor0 *info=(vorbis_info_floor0*)_ogg_malloc(sizeof(*info)); | |||||
| info->order=oggpack_read(opb,8); | |||||
| info->rate=oggpack_read(opb,16); | |||||
| info->barkmap=oggpack_read(opb,16); | |||||
| info->ampbits=oggpack_read(opb,6); | |||||
| info->ampdB=oggpack_read(opb,8); | |||||
| info->numbooks=oggpack_read(opb,4)+1; | |||||
| if(info->order<1)goto err_out; | |||||
| if(info->rate<1)goto err_out; | |||||
| if(info->barkmap<1)goto err_out; | |||||
| if(info->numbooks<1)goto err_out; | |||||
| for(j=0;j<info->numbooks;j++){ | |||||
| info->books[j]=oggpack_read(opb,8); | |||||
| if(info->books[j]<0 || info->books[j]>=ci->books)goto err_out; | |||||
| } | |||||
| return(info); | |||||
| err_out: | |||||
| floor0_free_info(info); | |||||
| return(NULL); | |||||
| } | |||||
| /* initialize Bark scale and normalization lookups. We could do this | |||||
| with static tables, but Vorbis allows a number of possible | |||||
| combinations, so it's best to do it computationally. | |||||
| The below is authoritative in terms of defining scale mapping. | |||||
| Note that the scale depends on the sampling rate as well as the | |||||
| linear block and mapping sizes */ | |||||
| static void floor0_map_lazy_init(vorbis_block *vb, | |||||
| vorbis_info_floor *infoX, | |||||
| vorbis_look_floor0 *look){ | |||||
| if(!look->linearmap[vb->W]){ | |||||
| vorbis_dsp_state *vd=vb->vd; | |||||
| vorbis_info *vi=vd->vi; | |||||
| codec_setup_info *ci=(codec_setup_info*)vi->codec_setup; | |||||
| vorbis_info_floor0 *info=(vorbis_info_floor0 *)infoX; | |||||
| int W=vb->W; | |||||
| int n=ci->blocksizes[W]/2,j; | |||||
| /* we choose a scaling constant so that: | |||||
| floor(bark(rate/2-1)*C)=mapped-1 | |||||
| floor(bark(rate/2)*C)=mapped */ | |||||
| float scale=look->ln/toBARK(info->rate/2.f); | |||||
| /* the mapping from a linear scale to a smaller bark scale is | |||||
| straightforward. We do *not* make sure that the linear mapping | |||||
| does not skip bark-scale bins; the decoder simply skips them and | |||||
| the encoder may do what it wishes in filling them. They're | |||||
| necessary in some mapping combinations to keep the scale spacing | |||||
| accurate */ | |||||
| look->linearmap[W]=(int*)_ogg_malloc((n+1)*sizeof(**look->linearmap)); | |||||
| for(j=0;j<n;j++){ | |||||
| int val=floor( toBARK((info->rate/2.f)/n*j) | |||||
| *scale); /* bark numbers represent band edges */ | |||||
| if(val>=look->ln)val=look->ln-1; /* guard against the approximation */ | |||||
| look->linearmap[W][j]=val; | |||||
| } | |||||
| look->linearmap[W][j]=-1; | |||||
| look->n[W]=n; | |||||
| } | |||||
| } | |||||
| static vorbis_look_floor *floor0_look(vorbis_dsp_state *vd, | |||||
| vorbis_info_floor *i){ | |||||
| vorbis_info_floor0 *info=(vorbis_info_floor0*)i; | |||||
| vorbis_look_floor0 *look=(vorbis_look_floor0*)_ogg_calloc(1,sizeof(*look)); | |||||
| look->m=info->order; | |||||
| look->ln=info->barkmap; | |||||
| look->vi=info; | |||||
| look->linearmap=(int**)_ogg_calloc(2,sizeof(*look->linearmap)); | |||||
| return look; | |||||
| } | |||||
| static void *floor0_inverse1(vorbis_block *vb,vorbis_look_floor *i){ | |||||
| vorbis_look_floor0 *look=(vorbis_look_floor0 *)i; | |||||
| vorbis_info_floor0 *info=look->vi; | |||||
| int j,k; | |||||
| int ampraw=oggpack_read(&vb->opb,info->ampbits); | |||||
| if(ampraw>0){ /* also handles the -1 out of data case */ | |||||
| long maxval=(1<<info->ampbits)-1; | |||||
| float amp=(float)ampraw/maxval*info->ampdB; | |||||
| int booknum=oggpack_read(&vb->opb,_ilog(info->numbooks)); | |||||
| if(booknum!=-1 && booknum<info->numbooks){ /* be paranoid */ | |||||
| codec_setup_info *ci=(codec_setup_info *)vb->vd->vi->codec_setup; | |||||
| codebook *b=ci->fullbooks+info->books[booknum]; | |||||
| float last=0.f; | |||||
| /* the additional b->dim is a guard against any possible stack | |||||
| smash; b->dim is provably more than we can overflow the | |||||
| vector */ | |||||
| float *lsp=(float*)_vorbis_block_alloc(vb,sizeof(*lsp)*(look->m+b->dim+1)); | |||||
| for(j=0;j<look->m;j+=b->dim) | |||||
| if(vorbis_book_decodev_set(b,lsp+j,&vb->opb,b->dim)==-1)goto eop; | |||||
| for(j=0;j<look->m;){ | |||||
| for(k=0;k<b->dim;k++,j++)lsp[j]+=last; | |||||
| last=lsp[j-1]; | |||||
| } | |||||
| lsp[look->m]=amp; | |||||
| return(lsp); | |||||
| } | |||||
| } | |||||
| eop: | |||||
| return(NULL); | |||||
| } | |||||
| static int floor0_inverse2(vorbis_block *vb,vorbis_look_floor *i, | |||||
| void *memo,float *out){ | |||||
| vorbis_look_floor0 *look=(vorbis_look_floor0 *)i; | |||||
| vorbis_info_floor0 *info=look->vi; | |||||
| floor0_map_lazy_init(vb,info,look); | |||||
| if(memo){ | |||||
| float *lsp=(float *)memo; | |||||
| float amp=lsp[look->m]; | |||||
| /* take the coefficients back to a spectral envelope curve */ | |||||
| vorbis_lsp_to_curve(out, | |||||
| look->linearmap[vb->W], | |||||
| look->n[vb->W], | |||||
| look->ln, | |||||
| lsp,look->m,amp,(float)info->ampdB); | |||||
| return(1); | |||||
| } | |||||
| memset(out,0,sizeof(*out)*look->n[vb->W]); | |||||
| return(0); | |||||
| } | |||||
| /* export hooks */ | |||||
| vorbis_func_floor floor0_exportbundle={ | |||||
| NULL,&floor0_unpack,&floor0_look,&floor0_free_info, | |||||
| &floor0_free_look,&floor0_inverse1,&floor0_inverse2 | |||||
| }; | |||||
| #endif | |||||
| @@ -0,0 +1,56 @@ | |||||
| /******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * | |||||
| * by the XIPHOPHORUS Company http://www.xiph.org/ * | |||||
| * * | |||||
| ******************************************************************** | |||||
| function: highlevel encoder setup struct seperated out for vorbisenc clarity | |||||
| last mod: $Id: highlevel.h,v 1.1 2007/06/07 17:49:17 jules_rms Exp $ | |||||
| ********************************************************************/ | |||||
| typedef struct highlevel_byblocktype { | |||||
| double tone_mask_setting; | |||||
| double tone_peaklimit_setting; | |||||
| double noise_bias_setting; | |||||
| double noise_compand_setting; | |||||
| } highlevel_byblocktype; | |||||
| typedef struct highlevel_encode_setup { | |||||
| void *setup; | |||||
| int set_in_stone; | |||||
| double base_setting; | |||||
| double long_setting; | |||||
| double short_setting; | |||||
| double impulse_noisetune; | |||||
| int managed; | |||||
| long bitrate_min; | |||||
| long bitrate_av; | |||||
| double bitrate_av_damp; | |||||
| long bitrate_max; | |||||
| long bitrate_reservoir; | |||||
| double bitrate_reservoir_bias; | |||||
| int impulse_block_p; | |||||
| int noise_normalize_p; | |||||
| double stereo_point_setting; | |||||
| double lowpass_kHz; | |||||
| double ath_floating_dB; | |||||
| double ath_absolute_dB; | |||||
| double amplitude_track_dBpersec; | |||||
| double trigger_setting; | |||||
| highlevel_byblocktype block[4]; /* padding, impulse, transition, long */ | |||||
| } highlevel_encode_setup; | |||||
| @@ -0,0 +1,602 @@ | |||||
| /******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2003 * | |||||
| * by the XIPHOPHORUS Company http://www.xiph.org/ * | |||||
| * * | |||||
| ******************************************************************** | |||||
| function: maintain the info structure, info <-> header packets | |||||
| last mod: $Id: info.c,v 1.1 2007/06/07 17:49:17 jules_rms Exp $ | |||||
| ********************************************************************/ | |||||
| #include "../../juce_OggVorbisHeader.h" | |||||
| #if JUCE_USE_OGGVORBIS | |||||
| /* general handling of the header and the vorbis_info structure (and | |||||
| substructures) */ | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| #include <ctype.h> | |||||
| #include "../../ogg.h" | |||||
| #include "../../codec.h" | |||||
| #include "codec_internal.h" | |||||
| #include "codebook.h" | |||||
| #include "registry.h" | |||||
| #include "window.h" | |||||
| #include "psy.h" | |||||
| #include "misc.h" | |||||
| #include "os.h" | |||||
| static void _v_writestring(oggpack_buffer *o, const char *s, int bytes){ | |||||
| while(bytes--){ | |||||
| oggpack_write(o,*s++,8); | |||||
| } | |||||
| } | |||||
| static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){ | |||||
| while(bytes--){ | |||||
| *buf++=oggpack_read(o,8); | |||||
| } | |||||
| } | |||||
| void vorbis_comment_init(vorbis_comment *vc){ | |||||
| memset(vc,0,sizeof(*vc)); | |||||
| } | |||||
| void vorbis_comment_add(vorbis_comment *vc,char *comment){ | |||||
| vc->user_comments=(char**)_ogg_realloc(vc->user_comments, | |||||
| (vc->comments+2)*sizeof(*vc->user_comments)); | |||||
| vc->comment_lengths=(int*)_ogg_realloc(vc->comment_lengths, | |||||
| (vc->comments+2)*sizeof(*vc->comment_lengths)); | |||||
| vc->comment_lengths[vc->comments]=strlen(comment); | |||||
| vc->user_comments[vc->comments]=(char*)_ogg_malloc(vc->comment_lengths[vc->comments]+1); | |||||
| strcpy(vc->user_comments[vc->comments], comment); | |||||
| vc->comments++; | |||||
| vc->user_comments[vc->comments]=NULL; | |||||
| } | |||||
| void vorbis_comment_add_tag(vorbis_comment *vc, const char *tag, char *contents){ | |||||
| char *comment=(char*)alloca(strlen(tag)+strlen(contents)+2); /* +2 for = and \0 */ | |||||
| strcpy(comment, tag); | |||||
| strcat(comment, "="); | |||||
| strcat(comment, contents); | |||||
| vorbis_comment_add(vc, comment); | |||||
| } | |||||
| /* This is more or less the same as strncasecmp - but that doesn't exist | |||||
| * everywhere, and this is a fairly trivial function, so we include it */ | |||||
| static int tagcompare(const char *s1, const char *s2, int n){ | |||||
| int c=0; | |||||
| while(c < n){ | |||||
| if(toupper(s1[c]) != toupper(s2[c])) | |||||
| return !0; | |||||
| c++; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count){ | |||||
| long i; | |||||
| int found = 0; | |||||
| int taglen = strlen(tag)+1; /* +1 for the = we append */ | |||||
| char *fulltag = (char*)alloca(taglen+ 1); | |||||
| strcpy(fulltag, tag); | |||||
| strcat(fulltag, "="); | |||||
| for(i=0;i<vc->comments;i++){ | |||||
| if(!tagcompare(vc->user_comments[i], fulltag, taglen)){ | |||||
| if(count == found) | |||||
| /* We return a pointer to the data, not a copy */ | |||||
| return vc->user_comments[i] + taglen; | |||||
| else | |||||
| found++; | |||||
| } | |||||
| } | |||||
| return NULL; /* didn't find anything */ | |||||
| } | |||||
| int vorbis_comment_query_count(vorbis_comment *vc, char *tag){ | |||||
| int i,count=0; | |||||
| int taglen = strlen(tag)+1; /* +1 for the = we append */ | |||||
| char *fulltag = (char*)alloca(taglen+1); | |||||
| strcpy(fulltag,tag); | |||||
| strcat(fulltag, "="); | |||||
| for(i=0;i<vc->comments;i++){ | |||||
| if(!tagcompare(vc->user_comments[i], fulltag, taglen)) | |||||
| count++; | |||||
| } | |||||
| return count; | |||||
| } | |||||
| void vorbis_comment_clear(vorbis_comment *vc){ | |||||
| if(vc){ | |||||
| long i; | |||||
| for(i=0;i<vc->comments;i++) | |||||
| if(vc->user_comments[i])_ogg_free(vc->user_comments[i]); | |||||
| if(vc->user_comments)_ogg_free(vc->user_comments); | |||||
| if(vc->comment_lengths)_ogg_free(vc->comment_lengths); | |||||
| if(vc->vendor)_ogg_free(vc->vendor); | |||||
| } | |||||
| memset(vc,0,sizeof(*vc)); | |||||
| } | |||||
| /* blocksize 0 is guaranteed to be short, 1 is guarantted to be long. | |||||
| They may be equal, but short will never ge greater than long */ | |||||
| int vorbis_info_blocksize(vorbis_info *vi,int zo){ | |||||
| codec_setup_info *ci = (codec_setup_info*)vi->codec_setup; | |||||
| return ci ? ci->blocksizes[zo] : -1; | |||||
| } | |||||
| /* used by synthesis, which has a full, alloced vi */ | |||||
| void vorbis_info_init(vorbis_info *vi){ | |||||
| memset(vi,0,sizeof(*vi)); | |||||
| vi->codec_setup=_ogg_calloc(1,sizeof(codec_setup_info)); | |||||
| } | |||||
| void vorbis_info_clear(vorbis_info *vi){ | |||||
| codec_setup_info *ci=(codec_setup_info*)vi->codec_setup; | |||||
| int i; | |||||
| if(ci){ | |||||
| for(i=0;i<ci->modes;i++) | |||||
| if(ci->mode_param[i])_ogg_free(ci->mode_param[i]); | |||||
| for(i=0;i<ci->maps;i++) /* unpack does the range checking */ | |||||
| _mapping_P[ci->map_type[i]]->free_info(ci->map_param[i]); | |||||
| for(i=0;i<ci->floors;i++) /* unpack does the range checking */ | |||||
| _floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]); | |||||
| for(i=0;i<ci->residues;i++) /* unpack does the range checking */ | |||||
| _residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]); | |||||
| for(i=0;i<ci->books;i++){ | |||||
| if(ci->book_param[i]){ | |||||
| /* knows if the book was not alloced */ | |||||
| vorbis_staticbook_destroy(ci->book_param[i]); | |||||
| } | |||||
| if(ci->fullbooks) | |||||
| vorbis_book_clear(ci->fullbooks+i); | |||||
| } | |||||
| if(ci->fullbooks) | |||||
| _ogg_free(ci->fullbooks); | |||||
| for(i=0;i<ci->psys;i++) | |||||
| _vi_psy_free(ci->psy_param[i]); | |||||
| _ogg_free(ci); | |||||
| } | |||||
| memset(vi,0,sizeof(*vi)); | |||||
| } | |||||
| /* Header packing/unpacking ********************************************/ | |||||
| static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){ | |||||
| codec_setup_info *ci=(codec_setup_info*)vi->codec_setup; | |||||
| if(!ci)return(OV_EFAULT); | |||||
| vi->version=oggpack_read(opb,32); | |||||
| if(vi->version!=0)return(OV_EVERSION); | |||||
| vi->channels=oggpack_read(opb,8); | |||||
| vi->rate=oggpack_read(opb,32); | |||||
| vi->bitrate_upper=oggpack_read(opb,32); | |||||
| vi->bitrate_nominal=oggpack_read(opb,32); | |||||
| vi->bitrate_lower=oggpack_read(opb,32); | |||||
| ci->blocksizes[0]=1<<oggpack_read(opb,4); | |||||
| ci->blocksizes[1]=1<<oggpack_read(opb,4); | |||||
| if(vi->rate<1)goto err_out; | |||||
| if(vi->channels<1)goto err_out; | |||||
| if(ci->blocksizes[0]<8)goto err_out; | |||||
| if(ci->blocksizes[1]<ci->blocksizes[0])goto err_out; | |||||
| if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ | |||||
| return(0); | |||||
| err_out: | |||||
| vorbis_info_clear(vi); | |||||
| return(OV_EBADHEADER); | |||||
| } | |||||
| static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){ | |||||
| int i; | |||||
| int vendorlen=oggpack_read(opb,32); | |||||
| if(vendorlen<0)goto err_out; | |||||
| vc->vendor=(char*)_ogg_calloc(vendorlen+1,1); | |||||
| _v_readstring(opb,vc->vendor,vendorlen); | |||||
| vc->comments=oggpack_read(opb,32); | |||||
| if(vc->comments<0)goto err_out; | |||||
| vc->user_comments=(char**)_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments)); | |||||
| vc->comment_lengths=(int*)_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths)); | |||||
| for(i=0;i<vc->comments;i++){ | |||||
| int len=oggpack_read(opb,32); | |||||
| if(len<0)goto err_out; | |||||
| vc->comment_lengths[i]=len; | |||||
| vc->user_comments[i]=(char*)_ogg_calloc(len+1,1); | |||||
| _v_readstring(opb,vc->user_comments[i],len); | |||||
| } | |||||
| if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ | |||||
| return(0); | |||||
| err_out: | |||||
| vorbis_comment_clear(vc); | |||||
| return(OV_EBADHEADER); | |||||
| } | |||||
| /* all of the real encoding details are here. The modes, books, | |||||
| everything */ | |||||
| static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){ | |||||
| codec_setup_info *ci=(codec_setup_info*)vi->codec_setup; | |||||
| int i; | |||||
| if(!ci)return(OV_EFAULT); | |||||
| /* codebooks */ | |||||
| ci->books=oggpack_read(opb,8)+1; | |||||
| /*ci->book_param=_ogg_calloc(ci->books,sizeof(*ci->book_param));*/ | |||||
| for(i=0;i<ci->books;i++){ | |||||
| ci->book_param[i]=(static_codebook*)_ogg_calloc(1,sizeof(*ci->book_param[i])); | |||||
| if(vorbis_staticbook_unpack(opb,ci->book_param[i]))goto err_out; | |||||
| } | |||||
| /* time backend settings; hooks are unused */ | |||||
| { | |||||
| int times=oggpack_read(opb,6)+1; | |||||
| for(i=0;i<times;i++){ | |||||
| int test=oggpack_read(opb,16); | |||||
| if(test<0 || test>=VI_TIMEB)goto err_out; | |||||
| } | |||||
| } | |||||
| /* floor backend settings */ | |||||
| ci->floors=oggpack_read(opb,6)+1; | |||||
| /*ci->floor_type=_ogg_malloc(ci->floors*sizeof(*ci->floor_type));*/ | |||||
| /*ci->floor_param=_ogg_calloc(ci->floors,sizeof(void *));*/ | |||||
| for(i=0;i<ci->floors;i++){ | |||||
| ci->floor_type[i]=oggpack_read(opb,16); | |||||
| if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out; | |||||
| ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb); | |||||
| if(!ci->floor_param[i])goto err_out; | |||||
| } | |||||
| /* residue backend settings */ | |||||
| ci->residues=oggpack_read(opb,6)+1; | |||||
| /*ci->residue_type=_ogg_malloc(ci->residues*sizeof(*ci->residue_type));*/ | |||||
| /*ci->residue_param=_ogg_calloc(ci->residues,sizeof(void *));*/ | |||||
| for(i=0;i<ci->residues;i++){ | |||||
| ci->residue_type[i]=oggpack_read(opb,16); | |||||
| if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out; | |||||
| ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb); | |||||
| if(!ci->residue_param[i])goto err_out; | |||||
| } | |||||
| /* map backend settings */ | |||||
| ci->maps=oggpack_read(opb,6)+1; | |||||
| /*ci->map_type=_ogg_malloc(ci->maps*sizeof(*ci->map_type));*/ | |||||
| /*ci->map_param=_ogg_calloc(ci->maps,sizeof(void *));*/ | |||||
| for(i=0;i<ci->maps;i++){ | |||||
| ci->map_type[i]=oggpack_read(opb,16); | |||||
| if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out; | |||||
| ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb); | |||||
| if(!ci->map_param[i])goto err_out; | |||||
| } | |||||
| /* mode settings */ | |||||
| ci->modes=oggpack_read(opb,6)+1; | |||||
| /*vi->mode_param=_ogg_calloc(vi->modes,sizeof(void *));*/ | |||||
| for(i=0;i<ci->modes;i++){ | |||||
| ci->mode_param[i]=(vorbis_info_mode*)_ogg_calloc(1,sizeof(*ci->mode_param[i])); | |||||
| ci->mode_param[i]->blockflag=oggpack_read(opb,1); | |||||
| ci->mode_param[i]->windowtype=oggpack_read(opb,16); | |||||
| ci->mode_param[i]->transformtype=oggpack_read(opb,16); | |||||
| ci->mode_param[i]->mapping=oggpack_read(opb,8); | |||||
| if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out; | |||||
| if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out; | |||||
| if(ci->mode_param[i]->mapping>=ci->maps)goto err_out; | |||||
| } | |||||
| if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */ | |||||
| return(0); | |||||
| err_out: | |||||
| vorbis_info_clear(vi); | |||||
| return(OV_EBADHEADER); | |||||
| } | |||||
| /* The Vorbis header is in three packets; the initial small packet in | |||||
| the first page that identifies basic parameters, a second packet | |||||
| with bitstream comments and a third packet that holds the | |||||
| codebook. */ | |||||
| int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){ | |||||
| oggpack_buffer opb; | |||||
| if(op){ | |||||
| oggpack_readinit(&opb,op->packet,op->bytes); | |||||
| /* Which of the three types of header is this? */ | |||||
| /* Also verify header-ness, vorbis */ | |||||
| { | |||||
| char buffer[6]; | |||||
| int packtype=oggpack_read(&opb,8); | |||||
| memset(buffer,0,6); | |||||
| _v_readstring(&opb,buffer,6); | |||||
| if(memcmp(buffer,"vorbis",6)){ | |||||
| /* not a vorbis header */ | |||||
| return(OV_ENOTVORBIS); | |||||
| } | |||||
| switch(packtype){ | |||||
| case 0x01: /* least significant *bit* is read first */ | |||||
| if(!op->b_o_s){ | |||||
| /* Not the initial packet */ | |||||
| return(OV_EBADHEADER); | |||||
| } | |||||
| if(vi->rate!=0){ | |||||
| /* previously initialized info header */ | |||||
| return(OV_EBADHEADER); | |||||
| } | |||||
| return(_vorbis_unpack_info(vi,&opb)); | |||||
| case 0x03: /* least significant *bit* is read first */ | |||||
| if(vi->rate==0){ | |||||
| /* um... we didn't get the initial header */ | |||||
| return(OV_EBADHEADER); | |||||
| } | |||||
| return(_vorbis_unpack_comment(vc,&opb)); | |||||
| case 0x05: /* least significant *bit* is read first */ | |||||
| if(vi->rate==0 || vc->vendor==NULL){ | |||||
| /* um... we didn;t get the initial header or comments yet */ | |||||
| return(OV_EBADHEADER); | |||||
| } | |||||
| return(_vorbis_unpack_books(vi,&opb)); | |||||
| default: | |||||
| /* Not a valid vorbis header type */ | |||||
| return(OV_EBADHEADER); | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| return(OV_EBADHEADER); | |||||
| } | |||||
| /* pack side **********************************************************/ | |||||
| static int _vorbis_pack_info(oggpack_buffer *opb,vorbis_info *vi){ | |||||
| codec_setup_info *ci=(codec_setup_info*)vi->codec_setup; | |||||
| if(!ci)return(OV_EFAULT); | |||||
| /* preamble */ | |||||
| oggpack_write(opb,0x01,8); | |||||
| _v_writestring(opb,"vorbis", 6); | |||||
| /* basic information about the stream */ | |||||
| oggpack_write(opb,0x00,32); | |||||
| oggpack_write(opb,vi->channels,8); | |||||
| oggpack_write(opb,vi->rate,32); | |||||
| oggpack_write(opb,vi->bitrate_upper,32); | |||||
| oggpack_write(opb,vi->bitrate_nominal,32); | |||||
| oggpack_write(opb,vi->bitrate_lower,32); | |||||
| oggpack_write(opb,ilog2(ci->blocksizes[0]),4); | |||||
| oggpack_write(opb,ilog2(ci->blocksizes[1]),4); | |||||
| oggpack_write(opb,1,1); | |||||
| return(0); | |||||
| } | |||||
| static int _vorbis_pack_comment(oggpack_buffer *opb,vorbis_comment *vc){ | |||||
| char temp[]="Xiph.Org libVorbis I 20050304"; | |||||
| int bytes = strlen(temp); | |||||
| /* preamble */ | |||||
| oggpack_write(opb,0x03,8); | |||||
| _v_writestring(opb,"vorbis", 6); | |||||
| /* vendor */ | |||||
| oggpack_write(opb,bytes,32); | |||||
| _v_writestring(opb,temp, bytes); | |||||
| /* comments */ | |||||
| oggpack_write(opb,vc->comments,32); | |||||
| if(vc->comments){ | |||||
| int i; | |||||
| for(i=0;i<vc->comments;i++){ | |||||
| if(vc->user_comments[i]){ | |||||
| oggpack_write(opb,vc->comment_lengths[i],32); | |||||
| _v_writestring(opb,vc->user_comments[i], vc->comment_lengths[i]); | |||||
| }else{ | |||||
| oggpack_write(opb,0,32); | |||||
| } | |||||
| } | |||||
| } | |||||
| oggpack_write(opb,1,1); | |||||
| return(0); | |||||
| } | |||||
| static int _vorbis_pack_books(oggpack_buffer *opb,vorbis_info *vi){ | |||||
| codec_setup_info *ci=(codec_setup_info*)vi->codec_setup; | |||||
| int i; | |||||
| if(!ci)return(OV_EFAULT); | |||||
| oggpack_write(opb,0x05,8); | |||||
| _v_writestring(opb,"vorbis", 6); | |||||
| /* books */ | |||||
| oggpack_write(opb,ci->books-1,8); | |||||
| for(i=0;i<ci->books;i++) | |||||
| if(vorbis_staticbook_pack(ci->book_param[i],opb))goto err_out; | |||||
| /* times; hook placeholders */ | |||||
| oggpack_write(opb,0,6); | |||||
| oggpack_write(opb,0,16); | |||||
| /* floors */ | |||||
| oggpack_write(opb,ci->floors-1,6); | |||||
| for(i=0;i<ci->floors;i++){ | |||||
| oggpack_write(opb,ci->floor_type[i],16); | |||||
| if(_floor_P[ci->floor_type[i]]->pack) | |||||
| _floor_P[ci->floor_type[i]]->pack(ci->floor_param[i],opb); | |||||
| else | |||||
| goto err_out; | |||||
| } | |||||
| /* residues */ | |||||
| oggpack_write(opb,ci->residues-1,6); | |||||
| for(i=0;i<ci->residues;i++){ | |||||
| oggpack_write(opb,ci->residue_type[i],16); | |||||
| _residue_P[ci->residue_type[i]]->pack(ci->residue_param[i],opb); | |||||
| } | |||||
| /* maps */ | |||||
| oggpack_write(opb,ci->maps-1,6); | |||||
| for(i=0;i<ci->maps;i++){ | |||||
| oggpack_write(opb,ci->map_type[i],16); | |||||
| _mapping_P[ci->map_type[i]]->pack(vi,ci->map_param[i],opb); | |||||
| } | |||||
| /* modes */ | |||||
| oggpack_write(opb,ci->modes-1,6); | |||||
| for(i=0;i<ci->modes;i++){ | |||||
| oggpack_write(opb,ci->mode_param[i]->blockflag,1); | |||||
| oggpack_write(opb,ci->mode_param[i]->windowtype,16); | |||||
| oggpack_write(opb,ci->mode_param[i]->transformtype,16); | |||||
| oggpack_write(opb,ci->mode_param[i]->mapping,8); | |||||
| } | |||||
| oggpack_write(opb,1,1); | |||||
| return(0); | |||||
| err_out: | |||||
| return(-1); | |||||
| } | |||||
| int vorbis_commentheader_out(vorbis_comment *vc, | |||||
| ogg_packet *op){ | |||||
| oggpack_buffer opb; | |||||
| oggpack_writeinit(&opb); | |||||
| if(_vorbis_pack_comment(&opb,vc)) return OV_EIMPL; | |||||
| op->packet = (unsigned char*) _ogg_malloc(oggpack_bytes(&opb)); | |||||
| memcpy(op->packet, opb.buffer, oggpack_bytes(&opb)); | |||||
| op->bytes=oggpack_bytes(&opb); | |||||
| op->b_o_s=0; | |||||
| op->e_o_s=0; | |||||
| op->granulepos=0; | |||||
| op->packetno=1; | |||||
| return 0; | |||||
| } | |||||
| int vorbis_analysis_headerout(vorbis_dsp_state *v, | |||||
| vorbis_comment *vc, | |||||
| ogg_packet *op, | |||||
| ogg_packet *op_comm, | |||||
| ogg_packet *op_code){ | |||||
| int ret=OV_EIMPL; | |||||
| vorbis_info *vi=v->vi; | |||||
| oggpack_buffer opb; | |||||
| private_state *b=(private_state*)v->backend_state; | |||||
| if(!b){ | |||||
| ret=OV_EFAULT; | |||||
| goto err_out; | |||||
| } | |||||
| /* first header packet **********************************************/ | |||||
| oggpack_writeinit(&opb); | |||||
| if(_vorbis_pack_info(&opb,vi))goto err_out; | |||||
| /* build the packet */ | |||||
| if(b->header)_ogg_free(b->header); | |||||
| b->header=(unsigned char*) _ogg_malloc(oggpack_bytes(&opb)); | |||||
| memcpy(b->header,opb.buffer,oggpack_bytes(&opb)); | |||||
| op->packet=b->header; | |||||
| op->bytes=oggpack_bytes(&opb); | |||||
| op->b_o_s=1; | |||||
| op->e_o_s=0; | |||||
| op->granulepos=0; | |||||
| op->packetno=0; | |||||
| /* second header packet (comments) **********************************/ | |||||
| oggpack_reset(&opb); | |||||
| if(_vorbis_pack_comment(&opb,vc))goto err_out; | |||||
| if(b->header1)_ogg_free(b->header1); | |||||
| b->header1=(unsigned char*) _ogg_malloc(oggpack_bytes(&opb)); | |||||
| memcpy(b->header1,opb.buffer,oggpack_bytes(&opb)); | |||||
| op_comm->packet=b->header1; | |||||
| op_comm->bytes=oggpack_bytes(&opb); | |||||
| op_comm->b_o_s=0; | |||||
| op_comm->e_o_s=0; | |||||
| op_comm->granulepos=0; | |||||
| op_comm->packetno=1; | |||||
| /* third header packet (modes/codebooks) ****************************/ | |||||
| oggpack_reset(&opb); | |||||
| if(_vorbis_pack_books(&opb,vi))goto err_out; | |||||
| if(b->header2)_ogg_free(b->header2); | |||||
| b->header2=(unsigned char*) _ogg_malloc(oggpack_bytes(&opb)); | |||||
| memcpy(b->header2,opb.buffer,oggpack_bytes(&opb)); | |||||
| op_code->packet=b->header2; | |||||
| op_code->bytes=oggpack_bytes(&opb); | |||||
| op_code->b_o_s=0; | |||||
| op_code->e_o_s=0; | |||||
| op_code->granulepos=0; | |||||
| op_code->packetno=2; | |||||
| oggpack_writeclear(&opb); | |||||
| return(0); | |||||
| err_out: | |||||
| oggpack_writeclear(&opb); | |||||
| memset(op,0,sizeof(*op)); | |||||
| memset(op_comm,0,sizeof(*op_comm)); | |||||
| memset(op_code,0,sizeof(*op_code)); | |||||
| if(b->header)_ogg_free(b->header); | |||||
| if(b->header1)_ogg_free(b->header1); | |||||
| if(b->header2)_ogg_free(b->header2); | |||||
| b->header=NULL; | |||||
| b->header1=NULL; | |||||
| b->header2=NULL; | |||||
| return(ret); | |||||
| } | |||||
| double vorbis_granule_time(vorbis_dsp_state *v,ogg_int64_t granulepos){ | |||||
| if(granulepos>=0) | |||||
| return((double)granulepos/v->vi->rate); | |||||
| return(-1); | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,99 @@ | |||||
| /******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * | |||||
| * by the XIPHOPHORUS Company http://www.xiph.org/ * | |||||
| * * | |||||
| ******************************************************************** | |||||
| function: lookup based functions | |||||
| last mod: $Id: lookup.c,v 1.1 2007/06/07 17:49:17 jules_rms Exp $ | |||||
| ********************************************************************/ | |||||
| #include "../../juce_OggVorbisHeader.h" | |||||
| #if JUCE_USE_OGGVORBIS | |||||
| #include <math.h> | |||||
| #include "lookup.h" | |||||
| #include "lookup_data.h" | |||||
| #include "os.h" | |||||
| #include "misc.h" | |||||
| #ifdef FLOAT_LOOKUP | |||||
| /* interpolated lookup based cos function, domain 0 to PI only */ | |||||
| float vorbis_coslook(float a){ | |||||
| double d=a*(.31830989*(float)COS_LOOKUP_SZ); | |||||
| int i=vorbis_ftoi(d-.5); | |||||
| return COS_LOOKUP[i]+ (d-i)*(COS_LOOKUP[i+1]-COS_LOOKUP[i]); | |||||
| } | |||||
| /* interpolated 1./sqrt(p) where .5 <= p < 1. */ | |||||
| float vorbis_invsqlook(float a){ | |||||
| double d=a*(2.f*(float)INVSQ_LOOKUP_SZ)-(float)INVSQ_LOOKUP_SZ; | |||||
| int i=vorbis_ftoi(d-.5f); | |||||
| return INVSQ_LOOKUP[i]+ (d-i)*(INVSQ_LOOKUP[i+1]-INVSQ_LOOKUP[i]); | |||||
| } | |||||
| /* interpolated 1./sqrt(p) where .5 <= p < 1. */ | |||||
| float vorbis_invsq2explook(int a){ | |||||
| return INVSQ2EXP_LOOKUP[a-INVSQ2EXP_LOOKUP_MIN]; | |||||
| } | |||||
| #include <stdio.h> | |||||
| /* interpolated lookup based fromdB function, domain -140dB to 0dB only */ | |||||
| float vorbis_fromdBlook(float a){ | |||||
| int i=vorbis_ftoi(a*((float)(-(1<<FROMdB2_SHIFT)))-.5f); | |||||
| return (i<0)?1.f: | |||||
| ((i>=(FROMdB_LOOKUP_SZ<<FROMdB_SHIFT))?0.f: | |||||
| FROMdB_LOOKUP[i>>FROMdB_SHIFT]*FROMdB2_LOOKUP[i&FROMdB2_MASK]); | |||||
| } | |||||
| #endif | |||||
| #ifdef INT_LOOKUP | |||||
| /* interpolated 1./sqrt(p) where .5 <= a < 1. (.100000... to .111111...) in | |||||
| 16.16 format | |||||
| returns in m.8 format */ | |||||
| long vorbis_invsqlook_i(long a,long e){ | |||||
| long i=(a&0x7fff)>>(INVSQ_LOOKUP_I_SHIFT-1); | |||||
| long d=(a&INVSQ_LOOKUP_I_MASK)<<(16-INVSQ_LOOKUP_I_SHIFT); /* 0.16 */ | |||||
| long val=INVSQ_LOOKUP_I[i]- /* 1.16 */ | |||||
| (((INVSQ_LOOKUP_I[i]-INVSQ_LOOKUP_I[i+1])* /* 0.16 */ | |||||
| d)>>16); /* result 1.16 */ | |||||
| e+=32; | |||||
| if(e&1)val=(val*5792)>>13; /* multiply val by 1/sqrt(2) */ | |||||
| e=(e>>1)-8; | |||||
| return(val>>e); | |||||
| } | |||||
| /* interpolated lookup based fromdB function, domain -140dB to 0dB only */ | |||||
| /* a is in n.12 format */ | |||||
| float vorbis_fromdBlook_i(long a){ | |||||
| int i=(-a)>>(12-FROMdB2_SHIFT); | |||||
| return (i<0)?1.f: | |||||
| ((i>=(FROMdB_LOOKUP_SZ<<FROMdB_SHIFT))?0.f: | |||||
| FROMdB_LOOKUP[i>>FROMdB_SHIFT]*FROMdB2_LOOKUP[i&FROMdB2_MASK]); | |||||
| } | |||||
| /* interpolated lookup based cos function, domain 0 to PI only */ | |||||
| /* a is in 0.16 format, where 0==0, 2^^16-1==PI, return 0.14 */ | |||||
| long vorbis_coslook_i(long a){ | |||||
| int i=a>>COS_LOOKUP_I_SHIFT; | |||||
| int d=a&COS_LOOKUP_I_MASK; | |||||
| return COS_LOOKUP_I[i]- ((d*(COS_LOOKUP_I[i]-COS_LOOKUP_I[i+1]))>> | |||||
| COS_LOOKUP_I_SHIFT); | |||||
| } | |||||
| #endif | |||||
| #endif | |||||
| @@ -0,0 +1,32 @@ | |||||
| /******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * | |||||
| * by the XIPHOPHORUS Company http://www.xiph.org/ * | |||||
| * * | |||||
| ******************************************************************** | |||||
| function: lookup based functions | |||||
| last mod: $Id: lookup.h,v 1.1 2007/06/07 17:49:17 jules_rms Exp $ | |||||
| ********************************************************************/ | |||||
| #ifndef _V_LOOKUP_H_ | |||||
| #ifdef FLOAT_LOOKUP | |||||
| extern float vorbis_coslook(float a); | |||||
| extern float vorbis_invsqlook(float a); | |||||
| extern float vorbis_invsq2explook(int a); | |||||
| extern float vorbis_fromdBlook(float a); | |||||
| #endif | |||||
| #ifdef INT_LOOKUP | |||||
| extern long vorbis_invsqlook_i(long a,long e); | |||||
| extern long vorbis_coslook_i(long a); | |||||
| extern float vorbis_fromdBlook_i(long a); | |||||
| #endif | |||||
| #endif | |||||
| @@ -0,0 +1,189 @@ | |||||
| /******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * | |||||
| * by the XIPHOPHORUS Company http://www.xiph.org/ * | |||||
| * * | |||||
| ******************************************************************** | |||||
| function: lookup data; generated by lookups.pl; edit there | |||||
| last mod: $Id: lookup_data.h,v 1.1 2007/06/07 17:49:17 jules_rms Exp $ | |||||
| ********************************************************************/ | |||||
| #ifndef _V_LOOKUP_DATA_H_ | |||||
| #ifdef FLOAT_LOOKUP | |||||
| #define COS_LOOKUP_SZ 128 | |||||
| static float COS_LOOKUP[COS_LOOKUP_SZ+1]={ | |||||
| +1.0000000000000f,+0.9996988186962f,+0.9987954562052f,+0.9972904566787f, | |||||
| +0.9951847266722f,+0.9924795345987f,+0.9891765099648f,+0.9852776423889f, | |||||
| +0.9807852804032f,+0.9757021300385f,+0.9700312531945f,+0.9637760657954f, | |||||
| +0.9569403357322f,+0.9495281805930f,+0.9415440651830f,+0.9329927988347f, | |||||
| +0.9238795325113f,+0.9142097557035f,+0.9039892931234f,+0.8932243011955f, | |||||
| +0.8819212643484f,+0.8700869911087f,+0.8577286100003f,+0.8448535652497f, | |||||
| +0.8314696123025f,+0.8175848131516f,+0.8032075314806f,+0.7883464276266f, | |||||
| +0.7730104533627f,+0.7572088465065f,+0.7409511253550f,+0.7242470829515f, | |||||
| +0.7071067811865f,+0.6895405447371f,+0.6715589548470f,+0.6531728429538f, | |||||
| +0.6343932841636f,+0.6152315905806f,+0.5956993044924f,+0.5758081914178f, | |||||
| +0.5555702330196f,+0.5349976198871f,+0.5141027441932f,+0.4928981922298f, | |||||
| +0.4713967368260f,+0.4496113296546f,+0.4275550934303f,+0.4052413140050f, | |||||
| +0.3826834323651f,+0.3598950365350f,+0.3368898533922f,+0.3136817403989f, | |||||
| +0.2902846772545f,+0.2667127574749f,+0.2429801799033f,+0.2191012401569f, | |||||
| +0.1950903220161f,+0.1709618887603f,+0.1467304744554f,+0.1224106751992f, | |||||
| +0.0980171403296f,+0.0735645635997f,+0.0490676743274f,+0.0245412285229f, | |||||
| +0.0000000000000f,-0.0245412285229f,-0.0490676743274f,-0.0735645635997f, | |||||
| -0.0980171403296f,-0.1224106751992f,-0.1467304744554f,-0.1709618887603f, | |||||
| -0.1950903220161f,-0.2191012401569f,-0.2429801799033f,-0.2667127574749f, | |||||
| -0.2902846772545f,-0.3136817403989f,-0.3368898533922f,-0.3598950365350f, | |||||
| -0.3826834323651f,-0.4052413140050f,-0.4275550934303f,-0.4496113296546f, | |||||
| -0.4713967368260f,-0.4928981922298f,-0.5141027441932f,-0.5349976198871f, | |||||
| -0.5555702330196f,-0.5758081914178f,-0.5956993044924f,-0.6152315905806f, | |||||
| -0.6343932841636f,-0.6531728429538f,-0.6715589548470f,-0.6895405447371f, | |||||
| -0.7071067811865f,-0.7242470829515f,-0.7409511253550f,-0.7572088465065f, | |||||
| -0.7730104533627f,-0.7883464276266f,-0.8032075314806f,-0.8175848131516f, | |||||
| -0.8314696123025f,-0.8448535652497f,-0.8577286100003f,-0.8700869911087f, | |||||
| -0.8819212643484f,-0.8932243011955f,-0.9039892931234f,-0.9142097557035f, | |||||
| -0.9238795325113f,-0.9329927988347f,-0.9415440651830f,-0.9495281805930f, | |||||
| -0.9569403357322f,-0.9637760657954f,-0.9700312531945f,-0.9757021300385f, | |||||
| -0.9807852804032f,-0.9852776423889f,-0.9891765099648f,-0.9924795345987f, | |||||
| -0.9951847266722f,-0.9972904566787f,-0.9987954562052f,-0.9996988186962f, | |||||
| -1.0000000000000f, | |||||
| }; | |||||
| #define INVSQ_LOOKUP_SZ 32 | |||||
| static float INVSQ_LOOKUP[INVSQ_LOOKUP_SZ+1]={ | |||||
| 1.414213562373f,1.392621247646f,1.371988681140f,1.352246807566f, | |||||
| 1.333333333333f,1.315191898443f,1.297771369046f,1.281025230441f, | |||||
| 1.264911064067f,1.249390095109f,1.234426799697f,1.219988562661f, | |||||
| 1.206045378311f,1.192569588000f,1.179535649239f,1.166919931983f, | |||||
| 1.154700538379f,1.142857142857f,1.131370849898f,1.120224067222f, | |||||
| 1.109400392450f,1.098884511590f,1.088662107904f,1.078719779941f, | |||||
| 1.069044967650f,1.059625885652f,1.050451462878f,1.041511287847f, | |||||
| 1.032795558989f,1.024295039463f,1.016001016002f,1.007905261358f, | |||||
| 1.000000000000f, | |||||
| }; | |||||
| #define INVSQ2EXP_LOOKUP_MIN (-32) | |||||
| #define INVSQ2EXP_LOOKUP_MAX 32 | |||||
| static float INVSQ2EXP_LOOKUP[INVSQ2EXP_LOOKUP_MAX-\ | |||||
| INVSQ2EXP_LOOKUP_MIN+1]={ | |||||
| 65536.f, 46340.95001f, 32768.f, 23170.47501f, | |||||
| 16384.f, 11585.2375f, 8192.f, 5792.618751f, | |||||
| 4096.f, 2896.309376f, 2048.f, 1448.154688f, | |||||
| 1024.f, 724.0773439f, 512.f, 362.038672f, | |||||
| 256.f, 181.019336f, 128.f, 90.50966799f, | |||||
| 64.f, 45.254834f, 32.f, 22.627417f, | |||||
| 16.f, 11.3137085f, 8.f, 5.656854249f, | |||||
| 4.f, 2.828427125f, 2.f, 1.414213562f, | |||||
| 1.f, 0.7071067812f, 0.5f, 0.3535533906f, | |||||
| 0.25f, 0.1767766953f, 0.125f, 0.08838834765f, | |||||
| 0.0625f, 0.04419417382f, 0.03125f, 0.02209708691f, | |||||
| 0.015625f, 0.01104854346f, 0.0078125f, 0.005524271728f, | |||||
| 0.00390625f, 0.002762135864f, 0.001953125f, 0.001381067932f, | |||||
| 0.0009765625f, 0.000690533966f, 0.00048828125f, 0.000345266983f, | |||||
| 0.000244140625f,0.0001726334915f,0.0001220703125f,8.631674575e-05f, | |||||
| 6.103515625e-05f,4.315837288e-05f,3.051757812e-05f,2.157918644e-05f, | |||||
| 1.525878906e-05f, | |||||
| }; | |||||
| #endif | |||||
| #define FROMdB_LOOKUP_SZ 35 | |||||
| #define FROMdB2_LOOKUP_SZ 32 | |||||
| #define FROMdB_SHIFT 5 | |||||
| #define FROMdB2_SHIFT 3 | |||||
| #define FROMdB2_MASK 31 | |||||
| static float FROMdB_LOOKUP[FROMdB_LOOKUP_SZ]={ | |||||
| 1.f, 0.6309573445f, 0.3981071706f, 0.2511886432f, | |||||
| 0.1584893192f, 0.1f, 0.06309573445f, 0.03981071706f, | |||||
| 0.02511886432f, 0.01584893192f, 0.01f, 0.006309573445f, | |||||
| 0.003981071706f, 0.002511886432f, 0.001584893192f, 0.001f, | |||||
| 0.0006309573445f,0.0003981071706f,0.0002511886432f,0.0001584893192f, | |||||
| 0.0001f,6.309573445e-05f,3.981071706e-05f,2.511886432e-05f, | |||||
| 1.584893192e-05f, 1e-05f,6.309573445e-06f,3.981071706e-06f, | |||||
| 2.511886432e-06f,1.584893192e-06f, 1e-06f,6.309573445e-07f, | |||||
| 3.981071706e-07f,2.511886432e-07f,1.584893192e-07f, | |||||
| }; | |||||
| static float FROMdB2_LOOKUP[FROMdB2_LOOKUP_SZ]={ | |||||
| 0.9928302478f, 0.9786445908f, 0.9646616199f, 0.9508784391f, | |||||
| 0.9372921937f, 0.92390007f, 0.9106992942f, 0.8976871324f, | |||||
| 0.8848608897f, 0.8722179097f, 0.8597555737f, 0.8474713009f, | |||||
| 0.835362547f, 0.8234268041f, 0.8116616003f, 0.8000644989f, | |||||
| 0.7886330981f, 0.7773650302f, 0.7662579617f, 0.755309592f, | |||||
| 0.7445176537f, 0.7338799116f, 0.7233941627f, 0.7130582353f, | |||||
| 0.7028699885f, 0.6928273125f, 0.6829281272f, 0.6731703824f, | |||||
| 0.6635520573f, 0.6540711597f, 0.6447257262f, 0.6355138211f, | |||||
| }; | |||||
| #ifdef INT_LOOKUP | |||||
| #define INVSQ_LOOKUP_I_SHIFT 10 | |||||
| #define INVSQ_LOOKUP_I_MASK 1023 | |||||
| static long INVSQ_LOOKUP_I[64+1]={ | |||||
| 92682l, 91966l, 91267l, 90583l, | |||||
| 89915l, 89261l, 88621l, 87995l, | |||||
| 87381l, 86781l, 86192l, 85616l, | |||||
| 85051l, 84497l, 83953l, 83420l, | |||||
| 82897l, 82384l, 81880l, 81385l, | |||||
| 80899l, 80422l, 79953l, 79492l, | |||||
| 79039l, 78594l, 78156l, 77726l, | |||||
| 77302l, 76885l, 76475l, 76072l, | |||||
| 75674l, 75283l, 74898l, 74519l, | |||||
| 74146l, 73778l, 73415l, 73058l, | |||||
| 72706l, 72359l, 72016l, 71679l, | |||||
| 71347l, 71019l, 70695l, 70376l, | |||||
| 70061l, 69750l, 69444l, 69141l, | |||||
| 68842l, 68548l, 68256l, 67969l, | |||||
| 67685l, 67405l, 67128l, 66855l, | |||||
| 66585l, 66318l, 66054l, 65794l, | |||||
| 65536l, | |||||
| }; | |||||
| #define COS_LOOKUP_I_SHIFT 9 | |||||
| #define COS_LOOKUP_I_MASK 511 | |||||
| #define COS_LOOKUP_I_SZ 128 | |||||
| static long COS_LOOKUP_I[COS_LOOKUP_I_SZ+1]={ | |||||
| 16384l, 16379l, 16364l, 16340l, | |||||
| 16305l, 16261l, 16207l, 16143l, | |||||
| 16069l, 15986l, 15893l, 15791l, | |||||
| 15679l, 15557l, 15426l, 15286l, | |||||
| 15137l, 14978l, 14811l, 14635l, | |||||
| 14449l, 14256l, 14053l, 13842l, | |||||
| 13623l, 13395l, 13160l, 12916l, | |||||
| 12665l, 12406l, 12140l, 11866l, | |||||
| 11585l, 11297l, 11003l, 10702l, | |||||
| 10394l, 10080l, 9760l, 9434l, | |||||
| 9102l, 8765l, 8423l, 8076l, | |||||
| 7723l, 7366l, 7005l, 6639l, | |||||
| 6270l, 5897l, 5520l, 5139l, | |||||
| 4756l, 4370l, 3981l, 3590l, | |||||
| 3196l, 2801l, 2404l, 2006l, | |||||
| 1606l, 1205l, 804l, 402l, | |||||
| 0l, -401l, -803l, -1204l, | |||||
| -1605l, -2005l, -2403l, -2800l, | |||||
| -3195l, -3589l, -3980l, -4369l, | |||||
| -4755l, -5138l, -5519l, -5896l, | |||||
| -6269l, -6638l, -7004l, -7365l, | |||||
| -7722l, -8075l, -8422l, -8764l, | |||||
| -9101l, -9433l, -9759l, -10079l, | |||||
| -10393l, -10701l, -11002l, -11296l, | |||||
| -11584l, -11865l, -12139l, -12405l, | |||||
| -12664l, -12915l, -13159l, -13394l, | |||||
| -13622l, -13841l, -14052l, -14255l, | |||||
| -14448l, -14634l, -14810l, -14977l, | |||||
| -15136l, -15285l, -15425l, -15556l, | |||||
| -15678l, -15790l, -15892l, -15985l, | |||||
| -16068l, -16142l, -16206l, -16260l, | |||||
| -16304l, -16339l, -16363l, -16378l, | |||||
| -16383l, | |||||
| }; | |||||
| #endif | |||||
| #endif | |||||
| @@ -0,0 +1,142 @@ | |||||
| #!/usr/bin/perl | |||||
| print <<'EOD'; | |||||
| /******************************************************************** | |||||
| * * | |||||
| * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * | |||||
| * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * | |||||
| * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * | |||||
| * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * | |||||
| * * | |||||
| * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * | |||||
| * by the XIPHOPHORUS Company http://www.xiph.org/ * | |||||
| * * | |||||
| ******************************************************************** | |||||
| function: lookup data; generated by lookups.pl; edit there | |||||
| last mod: $Id: lookups.pl,v 1.1 2007/06/07 17:49:17 jules_rms Exp $ | |||||
| ********************************************************************/ | |||||
| #ifndef _V_LOOKUP_DATA_H_ | |||||
| #ifdef FLOAT_LOOKUP | |||||
| EOD | |||||
| $cos_sz=128; | |||||
| $invsq_sz=32; | |||||
| $invsq2exp_min=-32; | |||||
| $invsq2exp_max=32; | |||||
| $fromdB_sz=35; | |||||
| $fromdB_shift=5; | |||||
| $fromdB2_shift=3; | |||||
| $invsq_i_shift=10; | |||||
| $cos_i_shift=9; | |||||
| $delta_shift=6; | |||||
| print "#define COS_LOOKUP_SZ $cos_sz\n"; | |||||
| print "static float COS_LOOKUP[COS_LOOKUP_SZ+1]={\n"; | |||||
| for($i=0;$i<=$cos_sz;){ | |||||
| print "\t"; | |||||
| for($j=0;$j<4 && $i<=$cos_sz;$j++){ | |||||
| printf "%+.13f,", cos(3.14159265358979323846*($i++)/$cos_sz) ; | |||||
| } | |||||
| print "\n"; | |||||
| } | |||||
| print "};\n\n"; | |||||
| print "#define INVSQ_LOOKUP_SZ $invsq_sz\n"; | |||||
| print "static float INVSQ_LOOKUP[INVSQ_LOOKUP_SZ+1]={\n"; | |||||
| for($i=0;$i<=$invsq_sz;){ | |||||
| print "\t"; | |||||
| for($j=0;$j<4 && $i<=$invsq_sz;$j++){ | |||||
| my$indexmap=$i++/$invsq_sz*.5+.5; | |||||
| printf "%.12f,", 1./sqrt($indexmap); | |||||
| } | |||||
| print "\n"; | |||||
| } | |||||
| print "};\n\n"; | |||||
| print "#define INVSQ2EXP_LOOKUP_MIN $invsq2exp_min\n"; | |||||
| print "#define INVSQ2EXP_LOOKUP_MAX $invsq2exp_max\n"; | |||||
| print "static float INVSQ2EXP_LOOKUP[INVSQ2EXP_LOOKUP_MAX-\\\n". | |||||
| " INVSQ2EXP_LOOKUP_MIN+1]={\n"; | |||||
| for($i=$invsq2exp_min;$i<=$invsq2exp_max;){ | |||||
| print "\t"; | |||||
| for($j=0;$j<4 && $i<=$invsq2exp_max;$j++){ | |||||
| printf "%15.10g,", 2**($i++*-.5); | |||||
| } | |||||
| print "\n"; | |||||
| } | |||||
| print "};\n\n#endif\n\n"; | |||||
| # 0 to -140 dB | |||||
| $fromdB2_sz=1<<$fromdB_shift; | |||||
| $fromdB_gran=1<<($fromdB_shift-$fromdB2_shift); | |||||
| print "#define FROMdB_LOOKUP_SZ $fromdB_sz\n"; | |||||
| print "#define FROMdB2_LOOKUP_SZ $fromdB2_sz\n"; | |||||
| print "#define FROMdB_SHIFT $fromdB_shift\n"; | |||||
| print "#define FROMdB2_SHIFT $fromdB2_shift\n"; | |||||
| print "#define FROMdB2_MASK ".((1<<$fromdB_shift)-1)."\n"; | |||||
| print "static float FROMdB_LOOKUP[FROMdB_LOOKUP_SZ]={\n"; | |||||
| for($i=0;$i<$fromdB_sz;){ | |||||
| print "\t"; | |||||
| for($j=0;$j<4 && $i<$fromdB_sz;$j++){ | |||||
| printf "%15.10g,", 10**(.05*(-$fromdB_gran*$i++)); | |||||
| } | |||||
| print "\n"; | |||||
| } | |||||
| print "};\n\n"; | |||||
| print "static float FROMdB2_LOOKUP[FROMdB2_LOOKUP_SZ]={\n"; | |||||
| for($i=0;$i<$fromdB2_sz;){ | |||||
| print "\t"; | |||||
| for($j=0;$j<4 && $i<$fromdB_sz;$j++){ | |||||
| printf "%15.10g,", 10**(.05*(-$fromdB_gran/$fromdB2_sz*(.5+$i++))); | |||||
| } | |||||
| print "\n"; | |||||
| } | |||||
| print "};\n\n#ifdef INT_LOOKUP\n\n"; | |||||
| $iisz=0x10000>>$invsq_i_shift; | |||||
| print "#define INVSQ_LOOKUP_I_SHIFT $invsq_i_shift\n"; | |||||
| print "#define INVSQ_LOOKUP_I_MASK ".(0x0ffff>>(16-$invsq_i_shift))."\n"; | |||||
| print "static long INVSQ_LOOKUP_I[$iisz+1]={\n"; | |||||
| for($i=0;$i<=$iisz;){ | |||||
| print "\t"; | |||||
| for($j=0;$j<4 && $i<=$iisz;$j++){ | |||||
| my$indexmap=$i++/$iisz*.5+.5; | |||||
| printf "%8d,", int(1./sqrt($indexmap)*65536.+.5); | |||||
| } | |||||
| print "\n"; | |||||
| } | |||||
| print "};\n\n"; | |||||
| $cisz=0x10000>>$cos_i_shift; | |||||
| print "#define COS_LOOKUP_I_SHIFT $cos_i_shift\n"; | |||||
| print "#define COS_LOOKUP_I_MASK ".(0x0ffff>>(16-$cos_i_shift))."\n"; | |||||
| print "#define COS_LOOKUP_I_SZ $cisz\n"; | |||||
| print "static long COS_LOOKUP_I[COS_LOOKUP_I_SZ+1]={\n"; | |||||
| for($i=0;$i<=$cisz;){ | |||||
| print "\t"; | |||||
| for($j=0;$j<4 && $i<=$cisz;$j++){ | |||||
| printf "%8d,", int(cos(3.14159265358979323846*($i++)/$cos_sz)*16384.+.5) ; | |||||
| } | |||||
| print "\n"; | |||||
| } | |||||
| print "};\n\n"; | |||||
| print "#endif\n\n#endif\n"; | |||||