- be gone, MultiVoc.

This commit is contained in:
Christoph Oelckers 2019-12-18 22:50:37 +01:00
parent 2cf9a4a626
commit a6395c0ed9
61 changed files with 2 additions and 18092 deletions

View file

@ -241,7 +241,7 @@ if( MSVC )
# Most of these need to be cleaned out. The source is currently infested with far too much conditional compilation which is a constant source of problems. # Most of these need to be cleaned out. The source is currently infested with far too much conditional compilation which is a constant source of problems.
set( ALL_C_FLAGS "${ALL_C_FLAGS} /DRENDERTYPESDL=1 /DMIXERTYPEWIN=1 /DSDL_USEFOLDER /DSDL_TARGET=2 /DUSE_OPENGL=1 /DSTARTUP_WINDOW /DUSE_LIBVPX /DHAVE_VORBIS /DHAVE_XMP /DNOASM=1 /DWIN32 /DLIBXMP_CORE_PLAYER" ) set( ALL_C_FLAGS "${ALL_C_FLAGS} /DRENDERTYPESDL=1 /DMIXERTYPEWIN=1 /DSDL_USEFOLDER /DSDL_TARGET=2 /DUSE_OPENGL=1 /DSTARTUP_WINDOW /DUSE_LIBVPX /DNOASM=1 /DWIN32" )
# The CMake configurations set /GR and /MD by default, which conflict with our settings. # The CMake configurations set /GR and /MD by default, which conflict with our settings.
string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} ) string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} )

View file

@ -1,371 +0,0 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000-2009 Josh Coalson
* Copyright (C) 2011-2013 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.
*/
#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"
/** \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/libtool.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

View file

@ -1,46 +0,0 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2001-2009 Josh Coalson
* Copyright (C) 2011-2013 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.
*/
#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

View file

@ -1,185 +0,0 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2004-2009 Josh Coalson
* Copyright (C) 2011-2013 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.
*/
#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

View file

@ -1,97 +0,0 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000-2009 Josh Coalson
* Copyright (C) 2011-2013 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.
*/
#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)
#define FLAC_API
#elif defined(_MSC_VER)
#ifdef FLAC_API_EXPORTS
#define FLAC_API _declspec(dllexport)
#else
#define FLAC_API _declspec(dllimport)
#endif
#elif defined(FLAC__USE_VISIBILITY_ATTR)
#define FLAC_API __attribute__ ((visibility ("default")))
#else
#define FLAC_API
#endif
/** These #defines will mirror the libtool-based library version number, see
* http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning
*/
#define FLAC_API_VERSION_CURRENT 11
#define FLAC_API_VERSION_REVISION 0 /**< see above */
#define FLAC_API_VERSION_AGE 3 /**< 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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,86 +0,0 @@
/* libFLAC - Free Lossless Audio Codec library
* Copyright (C) 2000-2009 Josh Coalson
* Copyright (C) 2011-2013 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.
*/
#ifndef FLAC__ORDINALS_H
#define FLAC__ORDINALS_H
#if defined(_MSC_VER) && _MSC_VER < 1600
/* Microsoft Visual Studio earlier than the 2010 version did not provide
* the 1999 ISO C Standard header file <stdint.h>.
*/
typedef __int8 FLAC__int8;
typedef unsigned __int8 FLAC__uint8;
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;
#else
/* For MSVC 2010 and everything else which provides <stdint.h>. */
#include <stdint.h>
typedef int8_t FLAC__int8;
typedef uint8_t FLAC__uint8;
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

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,25 +0,0 @@
#ifndef __CONFIG_TYPES_H__
#define __CONFIG_TYPES_H__
/* these are filled in by configure */
#define INCLUDE_INTTYPES_H 1
#define INCLUDE_STDINT_H 1
#define INCLUDE_SYS_TYPES_H 1
#if INCLUDE_INTTYPES_H
# include <inttypes.h>
#endif
#if INCLUDE_STDINT_H
# include <stdint.h>
#endif
#if INCLUDE_SYS_TYPES_H
# include <sys/types.h>
#endif
typedef int16_t ogg_int16_t;
typedef uint16_t ogg_uint16_t;
typedef int32_t ogg_int32_t;
typedef uint32_t ogg_uint32_t;
typedef int64_t ogg_int64_t;
#endif

View file

@ -1,210 +0,0 @@
/********************************************************************
* *
* 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-2007 *
* by the Xiph.Org Foundation http://www.xiph.org/ *
* *
********************************************************************
function: toplevel libogg include
last mod: $Id: ogg.h 18044 2011-08-01 17:55:20Z gmaxwell $
********************************************************************/
#ifndef _OGG_H
#define _OGG_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <ogg/os_types.h>
typedef struct {
void *iov_base;
size_t iov_len;
} ogg_iovec_t;
typedef struct {
long endbyte;
int endbit;
unsigned char *buffer;
unsigned char *ptr;
long storage;
} oggpack_buffer;
/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/
typedef struct {
unsigned char *header;
long header_len;
unsigned char *body;
long body_len;
} ogg_page;
/* ogg_stream_state contains the current encode/decode state of a logical
Ogg bitstream **********************************************************/
typedef struct {
unsigned char *body_data; /* bytes from packet bodies */
long body_storage; /* storage elements allocated */
long body_fill; /* elements stored; fill mark */
long body_returned; /* elements of fill returned */
int *lacing_vals; /* The values that will go to the segment table */
ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact
this way, but it is simple coupled to the
lacing fifo */
long lacing_storage;
long lacing_fill;
long lacing_packet;
long lacing_returned;
unsigned char header[282]; /* working space for header encode */
int header_fill;
int e_o_s; /* set when we have buffered the last packet in the
logical bitstream */
int b_o_s; /* set after we've written the initial page
of a logical bitstream */
long serialno;
long pageno;
ogg_int64_t packetno; /* sequence number for decode; the framing
knows where there's a hole in the data,
but we need coupling so that the codec
(which is in a separate abstraction
layer) also knows about the gap */
ogg_int64_t granulepos;
} ogg_stream_state;
/* ogg_packet is used to encapsulate the data and metadata belonging
to a single raw Ogg/Vorbis packet *************************************/
typedef struct {
unsigned char *packet;
long bytes;
long b_o_s;
long e_o_s;
ogg_int64_t granulepos;
ogg_int64_t packetno; /* sequence number for decode; the framing
knows where there's a hole in the data,
but we need coupling so that the codec
(which is in a separate abstraction
layer) also knows about the gap */
} ogg_packet;
typedef struct {
unsigned char *data;
int storage;
int fill;
int returned;
int unsynced;
int headerbytes;
int bodybytes;
} ogg_sync_state;
/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/
extern void oggpack_writeinit(oggpack_buffer *b);
extern int oggpack_writecheck(oggpack_buffer *b);
extern void oggpack_writetrunc(oggpack_buffer *b,long bits);
extern void oggpack_writealign(oggpack_buffer *b);
extern void oggpack_writecopy(oggpack_buffer *b,void *source,long bits);
extern void oggpack_reset(oggpack_buffer *b);
extern void oggpack_writeclear(oggpack_buffer *b);
extern void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
extern void oggpack_write(oggpack_buffer *b,unsigned long value,int bits);
extern long oggpack_look(oggpack_buffer *b,int bits);
extern long oggpack_look1(oggpack_buffer *b);
extern void oggpack_adv(oggpack_buffer *b,int bits);
extern void oggpack_adv1(oggpack_buffer *b);
extern long oggpack_read(oggpack_buffer *b,int bits);
extern long oggpack_read1(oggpack_buffer *b);
extern long oggpack_bytes(oggpack_buffer *b);
extern long oggpack_bits(oggpack_buffer *b);
extern unsigned char *oggpack_get_buffer(oggpack_buffer *b);
extern void oggpackB_writeinit(oggpack_buffer *b);
extern int oggpackB_writecheck(oggpack_buffer *b);
extern void oggpackB_writetrunc(oggpack_buffer *b,long bits);
extern void oggpackB_writealign(oggpack_buffer *b);
extern void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits);
extern void oggpackB_reset(oggpack_buffer *b);
extern void oggpackB_writeclear(oggpack_buffer *b);
extern void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
extern void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits);
extern long oggpackB_look(oggpack_buffer *b,int bits);
extern long oggpackB_look1(oggpack_buffer *b);
extern void oggpackB_adv(oggpack_buffer *b,int bits);
extern void oggpackB_adv1(oggpack_buffer *b);
extern long oggpackB_read(oggpack_buffer *b,int bits);
extern long oggpackB_read1(oggpack_buffer *b);
extern long oggpackB_bytes(oggpack_buffer *b);
extern long oggpackB_bits(oggpack_buffer *b);
extern unsigned char *oggpackB_get_buffer(oggpack_buffer *b);
/* Ogg BITSTREAM PRIMITIVES: encoding **************************/
extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op);
extern int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov,
int count, long e_o_s, ogg_int64_t granulepos);
extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og);
extern int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill);
extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og);
extern int ogg_stream_flush_fill(ogg_stream_state *os, ogg_page *og, int nfill);
/* Ogg BITSTREAM PRIMITIVES: decoding **************************/
extern int ogg_sync_init(ogg_sync_state *oy);
extern int ogg_sync_clear(ogg_sync_state *oy);
extern int ogg_sync_reset(ogg_sync_state *oy);
extern int ogg_sync_destroy(ogg_sync_state *oy);
extern int ogg_sync_check(ogg_sync_state *oy);
extern char *ogg_sync_buffer(ogg_sync_state *oy, long size);
extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes);
extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og);
extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og);
extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og);
extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op);
extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op);
/* Ogg BITSTREAM PRIMITIVES: general ***************************/
extern int ogg_stream_init(ogg_stream_state *os,int serialno);
extern int ogg_stream_clear(ogg_stream_state *os);
extern int ogg_stream_reset(ogg_stream_state *os);
extern int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno);
extern int ogg_stream_destroy(ogg_stream_state *os);
extern int ogg_stream_check(ogg_stream_state *os);
extern int ogg_stream_eos(ogg_stream_state *os);
extern void ogg_page_checksum_set(ogg_page *og);
extern int ogg_page_version(const ogg_page *og);
extern int ogg_page_continued(const ogg_page *og);
extern int ogg_page_bos(const ogg_page *og);
extern int ogg_page_eos(const ogg_page *og);
extern ogg_int64_t ogg_page_granulepos(const ogg_page *og);
extern int ogg_page_serialno(const ogg_page *og);
extern long ogg_page_pageno(const ogg_page *og);
extern int ogg_page_packets(const ogg_page *og);
extern void ogg_packet_clear(ogg_packet *op);
#ifdef __cplusplus
}
#endif
#endif /* _OGG_H */

View file

@ -1,147 +0,0 @@
/********************************************************************
* *
* 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: #ifdef jail to whip a few platforms into the UNIX ideal.
last mod: $Id: os_types.h 19098 2014-02-26 19:06:45Z giles $
********************************************************************/
#ifndef _OS_TYPES_H
#define _OS_TYPES_H
/* make it easy on the folks that want to compile the libs with a
different malloc than stdlib */
#define _ogg_malloc malloc
#define _ogg_calloc calloc
#define _ogg_realloc realloc
#define _ogg_free free
#if defined(_WIN32)
# if defined(__CYGWIN__)
# include <stdint.h>
typedef int16_t ogg_int16_t;
typedef uint16_t ogg_uint16_t;
typedef int32_t ogg_int32_t;
typedef uint32_t ogg_uint32_t;
typedef int64_t ogg_int64_t;
typedef uint64_t ogg_uint64_t;
# elif defined(__MINGW32__)
# include <sys/types.h>
typedef short ogg_int16_t;
typedef unsigned short ogg_uint16_t;
typedef int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef long long ogg_int64_t;
typedef unsigned long long ogg_uint64_t;
# elif defined(__MWERKS__)
typedef long long ogg_int64_t;
typedef int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef short ogg_int16_t;
typedef unsigned short ogg_uint16_t;
# else
/* MSVC/Borland */
typedef __int64 ogg_int64_t;
typedef __int32 ogg_int32_t;
typedef unsigned __int32 ogg_uint32_t;
typedef __int16 ogg_int16_t;
typedef unsigned __int16 ogg_uint16_t;
# endif
#elif defined(__MACOS__)
# include <sys/types.h>
typedef SInt16 ogg_int16_t;
typedef UInt16 ogg_uint16_t;
typedef SInt32 ogg_int32_t;
typedef UInt32 ogg_uint32_t;
typedef SInt64 ogg_int64_t;
#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
# include <inttypes.h>
typedef int16_t ogg_int16_t;
typedef uint16_t ogg_uint16_t;
typedef int32_t ogg_int32_t;
typedef uint32_t ogg_uint32_t;
typedef int64_t ogg_int64_t;
#elif defined(__HAIKU__)
/* Haiku */
# include <sys/types.h>
typedef short ogg_int16_t;
typedef unsigned short ogg_uint16_t;
typedef int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef long long ogg_int64_t;
#elif defined(__BEOS__)
/* Be */
# include <inttypes.h>
typedef int16_t ogg_int16_t;
typedef uint16_t ogg_uint16_t;
typedef int32_t ogg_int32_t;
typedef uint32_t ogg_uint32_t;
typedef int64_t ogg_int64_t;
#elif defined (__EMX__)
/* OS/2 GCC */
typedef short ogg_int16_t;
typedef unsigned short ogg_uint16_t;
typedef int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef long long ogg_int64_t;
#elif defined (DJGPP)
/* DJGPP */
typedef short ogg_int16_t;
typedef int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef long long ogg_int64_t;
#elif defined(R5900)
/* PS2 EE */
typedef long ogg_int64_t;
typedef int ogg_int32_t;
typedef unsigned ogg_uint32_t;
typedef short ogg_int16_t;
#elif defined(__SYMBIAN32__)
/* Symbian GCC */
typedef signed short ogg_int16_t;
typedef unsigned short ogg_uint16_t;
typedef signed int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef long long int ogg_int64_t;
#elif defined(__TMS320C6X__)
/* TI C64x compiler */
typedef signed short ogg_int16_t;
typedef unsigned short ogg_uint16_t;
typedef signed int ogg_int32_t;
typedef unsigned int ogg_uint32_t;
typedef long long int ogg_int64_t;
#else
# include <ogg/config_types.h>
#endif
#endif /* _OS_TYPES_H */

View file

@ -1,243 +0,0 @@
/********************************************************************
* *
* 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 Xiph.Org Foundation http://www.xiph.org/ *
********************************************************************
function: libvorbis codec headers
last mod: $Id: codec.h 17021 2010-03-24 09:29:41Z xiphmont $
********************************************************************/
#ifndef _vorbis_codec_h_
#define _vorbis_codec_h_
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
#include <ogg/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 independent 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, const char *comment);
extern void vorbis_comment_add_tag(vorbis_comment *vc,
const char *tag, const char *contents);
extern char *vorbis_comment_query(vorbis_comment *vc, const char *tag, int count);
extern int vorbis_comment_query_count(vorbis_comment *vc, const 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);
extern const char *vorbis_version_string(void);
/* 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_idheader(ogg_packet *op);
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

View file

@ -1,206 +0,0 @@
/********************************************************************
* *
* 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-2007 *
* by the Xiph.Org Foundation http://www.xiph.org/ *
* *
********************************************************************
function: stdio-based convenience library for opening/seeking/decoding
last mod: $Id: vorbisfile.h 17182 2010-04-29 03:48:32Z xiphmont $
********************************************************************/
#ifndef _OV_FILE_H_
#define _OV_FILE_H_
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
#include <stdio.h>
#include "codec.h"
/* The function prototypes for the callbacks are basically the same as for
* the stdio functions fread, fseek, fclose, ftell.
* The one difference is that the FILE * arguments have been replaced with
* a void * - this is to be used as a pointer to whatever internal data these
* functions might need. In the stdio case, it's just a FILE * cast to a void *
*
* If you use other functions, check the docs for these functions and return
* the right values. For seek_func(), you *MUST* return -1 if the stream is
* unseekable
*/
typedef struct {
size_t (*read_func) (void *ptr, size_t size, size_t nmemb, void *datasource);
int (*seek_func) (void *datasource, ogg_int64_t offset, int whence);
int (*close_func) (void *datasource);
long (*tell_func) (void *datasource);
} ov_callbacks;
#ifndef OV_EXCLUDE_STATIC_CALLBACKS
/* a few sets of convenient callbacks, especially for use under
* Windows where ov_open_callbacks() should always be used instead of
* ov_open() to avoid problems with incompatible crt.o version linking
* issues. */
static int _ov_header_fseek_wrap(FILE *f,ogg_int64_t off,int whence){
if(f==NULL)return(-1);
#ifdef __MINGW32__
return fseeko64(f,off,whence);
#elif defined (_WIN32)
return _fseeki64(f,off,whence);
#else
return fseek(f,off,whence);
#endif
}
/* These structs below (OV_CALLBACKS_DEFAULT etc) are defined here as
* static data. That means that every file which includes this header
* will get its own copy of these structs whether it uses them or
* not unless it #defines OV_EXCLUDE_STATIC_CALLBACKS.
* These static symbols are essential on platforms such as Windows on
* which several different versions of stdio support may be linked to
* by different DLLs, and we need to be certain we know which one
* we're using (the same one as the main application).
*/
static ov_callbacks OV_CALLBACKS_DEFAULT = {
(size_t (*)(void *, size_t, size_t, void *)) fread,
(int (*)(void *, ogg_int64_t, int)) _ov_header_fseek_wrap,
(int (*)(void *)) fclose,
(long (*)(void *)) ftell
};
static ov_callbacks OV_CALLBACKS_NOCLOSE = {
(size_t (*)(void *, size_t, size_t, void *)) fread,
(int (*)(void *, ogg_int64_t, int)) _ov_header_fseek_wrap,
(int (*)(void *)) NULL,
(long (*)(void *)) ftell
};
static ov_callbacks OV_CALLBACKS_STREAMONLY = {
(size_t (*)(void *, size_t, size_t, void *)) fread,
(int (*)(void *, ogg_int64_t, int)) NULL,
(int (*)(void *)) fclose,
(long (*)(void *)) NULL
};
static ov_callbacks OV_CALLBACKS_STREAMONLY_NOCLOSE = {
(size_t (*)(void *, size_t, size_t, void *)) fread,
(int (*)(void *, ogg_int64_t, int)) NULL,
(int (*)(void *)) NULL,
(long (*)(void *)) NULL
};
#endif
#define NOTOPEN 0
#define PARTOPEN 1
#define OPENED 2
#define STREAMSET 3
#define INITSET 4
typedef struct OggVorbis_File {
void *datasource; /* Pointer to a FILE *, etc. */
int seekable;
ogg_int64_t offset;
ogg_int64_t end;
ogg_sync_state oy;
/* If the FILE handle isn't seekable (eg, a pipe), only the current
stream appears */
int links;
ogg_int64_t *offsets;
ogg_int64_t *dataoffsets;
long *serialnos;
ogg_int64_t *pcmlengths; /* overloaded to maintain binary
compatibility; x2 size, stores both
beginning and end values */
vorbis_info *vi;
vorbis_comment *vc;
/* Decoding working state local storage */
ogg_int64_t pcm_offset;
int ready_state;
long current_serialno;
int current_link;
double bittrack;
double samptrack;
ogg_stream_state os; /* take physical pages, weld into a logical
stream of packets */
vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
vorbis_block vb; /* local working space for packet->PCM decode */
ov_callbacks callbacks;
} OggVorbis_File;
extern int ov_clear(OggVorbis_File *vf);
extern int ov_fopen(const char *path,OggVorbis_File *vf);
extern int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes);
extern int ov_open_callbacks(void *datasource, OggVorbis_File *vf,
const char *initial, long ibytes, ov_callbacks callbacks);
extern int ov_test(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes);
extern int ov_test_callbacks(void *datasource, OggVorbis_File *vf,
const char *initial, long ibytes, ov_callbacks callbacks);
extern int ov_test_open(OggVorbis_File *vf);
extern long ov_bitrate(OggVorbis_File *vf,int i);
extern long ov_bitrate_instant(OggVorbis_File *vf);
extern long ov_streams(OggVorbis_File *vf);
extern long ov_seekable(OggVorbis_File *vf);
extern long ov_serialnumber(OggVorbis_File *vf,int i);
extern ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i);
extern ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i);
extern double ov_time_total(OggVorbis_File *vf,int i);
extern int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos);
extern int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos);
extern int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos);
extern int ov_time_seek(OggVorbis_File *vf,double pos);
extern int ov_time_seek_page(OggVorbis_File *vf,double pos);
extern int ov_raw_seek_lap(OggVorbis_File *vf,ogg_int64_t pos);
extern int ov_pcm_seek_lap(OggVorbis_File *vf,ogg_int64_t pos);
extern int ov_pcm_seek_page_lap(OggVorbis_File *vf,ogg_int64_t pos);
extern int ov_time_seek_lap(OggVorbis_File *vf,double pos);
extern int ov_time_seek_page_lap(OggVorbis_File *vf,double pos);
extern ogg_int64_t ov_raw_tell(OggVorbis_File *vf);
extern ogg_int64_t ov_pcm_tell(OggVorbis_File *vf);
extern double ov_time_tell(OggVorbis_File *vf);
extern vorbis_info *ov_info(OggVorbis_File *vf,int link);
extern vorbis_comment *ov_comment(OggVorbis_File *vf,int link);
extern long ov_read_float(OggVorbis_File *vf,float ***pcm_channels,int samples,
int *bitstream);
extern long ov_read_filter(OggVorbis_File *vf,char *buffer,int length,
int bigendianp,int word,int sgned,int *bitstream,
void (*filter)(float **pcm,long channels,long samples,void *filter_param),void *filter_param);
extern long ov_read(OggVorbis_File *vf,char *buffer,int length,
int bigendianp,int word,int sgned,int *bitstream);
extern int ov_crosslap(OggVorbis_File *vf1,OggVorbis_File *vf2);
extern int ov_halfrate(OggVorbis_File *vf,int flag);
extern int ov_halfrate_p(OggVorbis_File *vf);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif

Binary file not shown.

Binary file not shown.

View file

@ -104,10 +104,7 @@ if( WIN32 )
libSDL2main libSDL2main
libSDL2 libSDL2
# this local library crap needs to go away. The Ogg/Vorbis libraries are easy to replace with libsndfile but there doesn't seem to be anything to get a working libvpx that doesn't force linking with MinGW dependencies. # this local library crap needs to go away. Sadly there doesn't seem to be anything to get a working libvpx that doesn't force linking with MinGW dependencies.
libogg
libvorbis
libvorbisfile
libvpx libvpx
libcompat-to-msvc libcompat-to-msvc

View file

@ -1,339 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View file

@ -1,45 +0,0 @@
/*
Copyright (C) 1994-1995 Apogee Software, Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __AL_MIDI_H
#define __AL_MIDI_H
#include "opl3.h"
#include <inttypes.h>
typedef struct
{
uint8_t SAVEK[2];
uint8_t Level[2];
uint8_t Env1[2];
uint8_t Env2[2];
uint8_t Wave[2];
uint8_t Feedback;
int8_t Transpose;
int8_t Velocity;
} AdLibTimbre;
extern AdLibTimbre ADLIB_TimbreBank[256];
opl3_chip *AL_GetChip(void);
void AL_RegisterTimbreBank(uint8_t const *timbres);
void AL_SetStereo(int const stereo);
#endif

View file

@ -1,56 +0,0 @@
/*
Copyright (C) 2009 Jonathon Fowler <jf@jonof.id.au>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef DRIVERS_H
#define DRIVERS_H
#include "sndcards.h"
#include "midifuncs.h"
extern int ASS_PCMSoundDriver;
extern int ASS_MIDISoundDriver;
extern int ASS_EMIDICard;
int SoundDriver_IsPCMSupported(int driver);
int SoundDriver_IsMIDISupported(int driver);
const char *SoundDriver_GetName(int driver);
int SoundDriver_PCM_GetError(void);
const char *SoundDriver_PCM_ErrorString(int ErrorNumber);
int SoundDriver_MIDI_GetError(void);
const char *SoundDriver_MIDI_ErrorString(int ErrorNumber);
int SoundDriver_PCM_Init(int *mixrate, int *numchannels, void *initdata);
void SoundDriver_PCM_Shutdown(void);
int SoundDriver_PCM_BeginPlayback(char *BufferStart, int BufferSize, int NumDivisions, void (*CallBackFunc)(void));
void SoundDriver_PCM_StopPlayback(void);
void SoundDriver_PCM_Lock(void);
void SoundDriver_PCM_Unlock(void);
int SoundDriver_MIDI_Init(midifuncs *);
void SoundDriver_MIDI_Shutdown(void);
int SoundDriver_MIDI_StartPlayback(void (*service)(void));
void SoundDriver_MIDI_HaltPlayback(void);
void SoundDriver_MIDI_SetTempo(int tempo, int division);
void SoundDriver_MIDI_Lock(void);
void SoundDriver_MIDI_Unlock(void);
#endif

View file

@ -1,116 +0,0 @@
/*
Copyright (C) 1994-1995 Apogee Software, Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**********************************************************************
module: FX_MAN.H
author: James R. Dose
date: March 17, 1994
Public header for FX_MAN.C
(c) Copyright 1994 James R. Dose. All Rights Reserved.
**********************************************************************/
#ifndef FX_MAN_H_
#define FX_MAN_H_
#include "drivers.h"
#include <inttypes.h>
#include "limits.h"
#include "multivoc.h"
enum FX_ERRORS
{
FX_Warning = -2,
FX_Error = -1,
FX_Ok = 0,
FX_InvalidCard,
FX_MultiVocError,
};
enum FX_LOOP_HOW
{
FX_ONESHOT = -1,
FX_LOOP = 0,
};
#define FX_MUSIC_PRIORITY INT_MAX
const char *FX_ErrorString(int ErrorNumber);
int FX_Init(int numvoices, int numchannels, int mixrate, void *initdata);
int FX_Shutdown(void);
int FX_GetDevice(void);
int FX_Play(char *ptr, uint32_t ptrlength, int loopstart, int loopend, int pitchoffset,
int vol, int left, int right, int priority, float volume, intptr_t callbackval);
int FX_Play3D(char *ptr, uint32_t ptrlength, int loophow, int pitchoffset, int angle,
int distance, int priority, float volume, intptr_t callbackval);
int FX_PlayRaw(char *ptr, uint32_t ptrlength, int rate, int pitchoffset, int vol,
int left, int right, int priority, float volume, intptr_t callbackval);
int FX_PlayLoopedRaw(char *ptr, uint32_t ptrlength, char *loopstart, char *loopend, int rate,
int pitchoffset, int vol, int left, int right, int priority, float volume, intptr_t callbackval);
int FX_SetPrintf(void(*function)(const char *, ...));
extern int FX_ErrorCode;
#define FX_SetErrorCode(status) FX_ErrorCode = (status);
static FORCE_INLINE int FX_CheckMVErr(int status)
{
if (status != MV_Ok)
{
FX_SetErrorCode(FX_MultiVocError);
status = FX_Warning;
}
return status;
}
static FORCE_INLINE void FX_SetCallBack(void(*function)(intptr_t)) { MV_SetCallBack(function); }
static FORCE_INLINE void FX_SetVolume(int volume) { MV_SetVolume(volume); }
static FORCE_INLINE int FX_GetVolume(void) { return MV_GetVolume(); }
static FORCE_INLINE void FX_SetReverseStereo(int setting) { MV_SetReverseStereo(setting); }
static FORCE_INLINE int FX_GetReverseStereo(void) { return MV_GetReverseStereo(); }
static FORCE_INLINE void FX_SetReverb_(int reverb) { MV_SetReverb(reverb); }
static FORCE_INLINE int FX_GetMaxReverbDelay(void) { return MV_GetMaxReverbDelay(); }
static FORCE_INLINE int FX_GetReverbDelay(void) { return MV_GetReverbDelay(); }
static FORCE_INLINE int FX_VoiceAvailable(int priority) { return MV_VoiceAvailable(priority); }
static FORCE_INLINE int FX_PauseVoice(int handle, int pause) { return FX_CheckMVErr(MV_PauseVoice(handle, pause)); }
static FORCE_INLINE int FX_EndLooping(int handle) { return FX_CheckMVErr(MV_EndLooping(handle)); }
static FORCE_INLINE int FX_SetPan(int handle, int vol, int left, int right)
{
return FX_CheckMVErr(MV_SetPan(handle, vol, left, right));
}
static FORCE_INLINE int FX_SetPitch(int handle, int pitchoffset) { return FX_CheckMVErr(MV_SetPitch(handle, pitchoffset)); }
static FORCE_INLINE int FX_SetFrequency(int handle, int frequency) { return FX_CheckMVErr(MV_SetFrequency(handle, frequency)); }
static FORCE_INLINE int FX_Pan3D(int handle, int angle, int distance)
{
return FX_CheckMVErr(MV_Pan3D(handle, angle, distance));
}
static FORCE_INLINE int FX_SoundActive(int handle) { return MV_VoicePlaying(handle); }
static FORCE_INLINE int FX_SoundValidAndActive(int handle) { return handle > 0 && MV_VoicePlaying(handle); }
static FORCE_INLINE int FX_SoundsPlaying(void) { return MV_VoicesPlaying(); }
static FORCE_INLINE int FX_StopSound(int handle) { return FX_CheckMVErr(MV_Kill(handle)); }
static FORCE_INLINE int FX_StopAllSounds_(void) { return FX_CheckMVErr(MV_KillAllVoices()); }
#endif

View file

@ -1,39 +0,0 @@
/*
Copyright (C) 1994-1995 Apogee Software, Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __MIDIFUNCS_H
#define __MIDIFUNCS_H
typedef struct
{
void ( *NoteOff )( int channel, int key, int velocity );
void ( *NoteOn )( int channel, int key, int velocity );
void ( *PolyAftertouch )( int channel, int key, int pressure );
void ( *ControlChange )( int channel, int number, int value );
void ( *ProgramChange )( int channel, int program );
void ( *ChannelAftertouch )( int channel, int pressure );
void ( *PitchBend )( int channel, int lsb, int msb );
void ( *ReleasePatches )( void );
void ( *LoadPatch )( int number );
void ( *SetVolume )( int volume );
int ( *GetVolume )( void );
void ( *SysEx )( const unsigned char * data, int length );
} midifuncs;
#endif

View file

@ -1,138 +0,0 @@
/*
Copyright (C) 1994-1995 Apogee Software, Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**********************************************************************
file: MULTIVOC.H
author: James R. Dose
date: December 20, 1993
Public header for MULTIVOC.C
(c) Copyright 1993 James R. Dose. All Rights Reserved.
**********************************************************************/
#ifndef MULTIVOC_H_
#define MULTIVOC_H_
#include "compat.h"
#include "drivers.h"
typedef enum : char
{
FMT_UNKNOWN,
FMT_RAW,
FMT_VOC,
FMT_WAV,
FMT_SNDFILE,
FMT_ZMUSIC,
// soon to be obsolete.
FMT_VORBIS,
FMT_FLAC,
FMT_MAX
} wavefmt_t;
#define MV_MINVOICEHANDLE 1
extern int MV_ErrorCode;
enum MV_Errors
{
MV_Error = -1,
MV_Ok = 0,
MV_NotInstalled,
MV_DriverError,
MV_NoVoices,
MV_NoMem,
MV_VoiceNotFound,
MV_InvalidFile,
};
extern void (*MV_Printf)(const char *fmt, ...);
extern int MV_Locked;
static inline void MV_Lock(void)
{
if (!MV_Locked++)
SoundDriver_PCM_Lock();
}
static inline void MV_Unlock(void)
{
if (!--MV_Locked)
SoundDriver_PCM_Unlock();
else if (MV_Locked < 0)
MV_Printf("MV_Unlock(): lockdepth < 0!\n");
}
const char *MV_ErrorString(int ErrorNumber);
int MV_VoicePlaying(int handle);
int MV_KillAllVoices(void);
int MV_Kill(int handle);
int MV_VoicesPlaying(void);
int MV_VoiceAvailable(int priority);
int MV_SetPitch(int handle, int pitchoffset);
int MV_SetFrequency(int handle, int frequency);
int MV_PauseVoice(int handle, int pause);
int MV_EndLooping(int handle);
int MV_SetPan(int handle, int vol, int left, int right);
int MV_Pan3D(int handle, int angle, int distance);
void MV_SetReverb(int reverb);
int MV_GetMaxReverbDelay(void);
int MV_GetReverbDelay(void);
void MV_SetReverbDelay(int delay);
int MV_PlayVOC3D(char *ptr, uint32_t length, int loophow, int pitchoffset, int angle, int distance,
int priority, float volume, intptr_t callbackval);
int MV_PlayVOC(char *ptr, uint32_t length, int loopstart, int loopend, int pitchoffset, int vol,
int left, int right, int priority, float volume, intptr_t callbackval);
decltype(MV_PlayVOC3D) MV_PlayWAV3D;
decltype(MV_PlayVOC) MV_PlayWAV;
decltype(MV_PlayVOC3D) MV_PlayVorbis3D;
decltype(MV_PlayVOC) MV_PlayVorbis;
decltype(MV_PlayVOC3D) MV_PlayFLAC3D;
decltype(MV_PlayVOC) MV_PlayFLAC;
int MV_PlayRAW(char *ptr, uint32_t length, int rate, char *loopstart, char *loopend, int pitchoffset, int vol,
int left, int right, int priority, float volume, intptr_t callbackval);
int MV_GetPosition(int handle, int *position);
int MV_SetPosition(int handle, int position);
void MV_SetVolume(int volume);
int MV_GetVolume(void);
void MV_SetCallBack(void (*function)(intptr_t));
void MV_SetReverseStereo(int setting);
int MV_GetReverseStereo(void);
int MV_Init(int soundcard, int MixRate, int Voices, int numchannels, void *initdata);
int MV_Shutdown(void);
void MV_HookMusicRoutine(void (*callback)(void));
void MV_UnhookMusicRoutine(void);
struct MV_MusicRoutineBuffer
{
char * buffer;
int32_t size;
};
struct MV_MusicRoutineBuffer MV_GetMusicRoutineBuffer(void);
static inline void MV_SetPrintf(void (*function)(const char *, ...)) { if (function) MV_Printf = function; }
#endif

View file

@ -1,75 +0,0 @@
/*
Copyright (C) 1994-1995 Apogee Software, Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Modifications for JonoF's port by Jonathon Fowler (jf@jonof.id.au)
*/
/**********************************************************************
module: MUSIC.H
author: James R. Dose
date: March 25, 1994
Public header for MUSIC.C
(c) Copyright 1994 James R. Dose. All Rights Reserved.
**********************************************************************/
#ifndef __MUSIC_H
#define __MUSIC_H
#include "compat.h"
extern int MUSIC_ErrorCode;
enum MUSIC_ERRORS
{
MUSIC_Warning = -2,
MUSIC_Error = -1,
MUSIC_Ok = 0,
MUSIC_MidiError,
};
typedef struct
{
uint32_t tickposition;
uint32_t milliseconds;
uint32_t measure;
uint32_t beat;
uint32_t tick;
} songposition;
#define MUSIC_LoopSong ( 1 == 1 )
#define MUSIC_PlayOnce ( !MUSIC_LoopSong )
#define MUSIC_SetErrorCode(status) MUSIC_ErrorCode = (status);
extern const char *MUSIC_ErrorString(int ErrorNumber);
int MUSIC_Init(int SoundCard);
int MUSIC_Shutdown(void);
int MIDI_GetDevice(void);
void MUSIC_SetVolume(int volume);
int MUSIC_GetVolume(void);
void MUSIC_SetLoopFlag(int loopflag);
void MUSIC_Continue(void);
void MUSIC_Pause(void);
int MUSIC_StopSong(void);
int MUSIC_PlaySong(char *song, int songsize, int loopflag, const char *fn = nullptr);
void MUSIC_Update(void);
#endif

View file

@ -1,160 +0,0 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2013-2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
//
// Nuked OPL3 emulator.
// Thanks:
// MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh):
// Feedback and Rhythm part calculation information.
// forums.submarine.org.uk(carbon14, opl3):
// Tremolo and phase generator calculation information.
// OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
// OPL2 ROMs.
// siliconpr0n.org(John McMaster, digshadow):
// YMF262 and VRC VII decaps and die shots.
//
// version: 1.8
//
#ifndef OPL_OPL3_H
#define OPL_OPL3_H
#include <inttypes.h>
#define OPL_WRITEBUF_SIZE 1024
#define OPL_WRITEBUF_DELAY 2
typedef uintptr_t Bitu;
typedef intptr_t Bits;
typedef uint64_t Bit64u;
typedef int64_t Bit64s;
typedef uint32_t Bit32u;
typedef int32_t Bit32s;
typedef uint16_t Bit16u;
typedef int16_t Bit16s;
typedef uint8_t Bit8u;
typedef int8_t Bit8s;
typedef struct _opl3_slot opl3_slot;
typedef struct _opl3_channel opl3_channel;
typedef struct _opl3_chip opl3_chip;
struct _opl3_slot {
opl3_channel *channel;
opl3_chip *chip;
Bit16s out;
Bit16s fbmod;
Bit16s *mod;
Bit16s prout;
Bit16s eg_rout;
Bit16s eg_out;
Bit8u eg_inc;
Bit8u eg_gen;
Bit8u eg_rate;
Bit8u eg_ksl;
Bit8u *trem;
Bit8u reg_vib;
Bit8u reg_type;
Bit8u reg_ksr;
Bit8u reg_mult;
Bit8u reg_ksl;
Bit8u reg_tl;
Bit8u reg_ar;
Bit8u reg_dr;
Bit8u reg_sl;
Bit8u reg_rr;
Bit8u reg_wf;
Bit8u key;
Bit32u pg_reset;
Bit32u pg_phase;
Bit16u pg_phase_out;
Bit8u slot_num;
};
struct _opl3_channel {
opl3_slot *slots[2];
opl3_channel *pair;
opl3_chip *chip;
Bit16s *out[4];
Bit8u chtype;
Bit16u f_num;
Bit8u block;
Bit8u fb;
Bit8u con;
Bit8u alg;
Bit8u ksv;
Bit16u cha, chb;
Bit32s leftpan;
Bit32s rightpan;
Bit8u ch_num;
};
typedef struct _opl3_writebuf {
Bit64u time;
Bit16u reg;
Bit8u data;
} opl3_writebuf;
struct _opl3_chip {
opl3_channel channel[18];
opl3_slot slot[36];
Bit16u timer;
Bit64u eg_timer;
Bit8u eg_timerrem;
Bit8u eg_state;
Bit8u eg_add;
Bit8u newm;
Bit8u nts;
Bit8u rhy;
Bit8u vibpos;
Bit8u vibshift;
Bit8u tremolo;
Bit8u tremolopos;
Bit8u tremoloshift;
Bit32u noise;
Bit16s zeromod;
Bit32s mixbuff[2];
Bit8u rm_hh_bit2;
Bit8u rm_hh_bit3;
Bit8u rm_hh_bit7;
Bit8u rm_hh_bit8;
Bit8u rm_tc_bit3;
Bit8u rm_tc_bit5;
Bit8u stereoext;
Bit32s rateratio;
Bit32s samplecnt;
Bit16s oldsamples[2];
Bit16s samples[2];
Bit64u writebuf_samplecnt;
Bit32u writebuf_cur;
Bit32u writebuf_last;
Bit64u writebuf_lasttime;
opl3_writebuf writebuf[OPL_WRITEBUF_SIZE];
};
void OPL3_Generate(opl3_chip *chip, Bit16s *buf);
void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf);
void OPL3_Reset(opl3_chip *chip, Bit32u samplerate);
void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v);
void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v);
void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples);
#endif

View file

@ -1,144 +0,0 @@
/*
* Copyright by Hannu Savolainen 1993-1996
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. 2.
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
// heavily modified for audiolib
// original definitions found at http://www.cs.albany.edu/~sdc/Linux/linux-2.0/drivers/sound/opl3.h
// it's from old Linux source but the license is pretty clearly 2-clause BSD.
#ifndef opl3_reg_h__
#define OPL3_opl3_reg_h__
#define OPL3_TEST_REGISTER 0x01
#define OPL3_ENABLE_WAVE_SELECT 0x20
#define OPL3_TIMER1_REGISTER 0x02
#define OPL3_TIMER2_REGISTER 0x03
#define OPL3_TIMER_CONTROL_REGISTER 0x04 /* Left side */
#define OPL3_IRQ_RESET 0x80
#define OPL3_TIMER1_MASK 0x40
#define OPL3_TIMER2_MASK 0x20
#define OPL3_TIMER1_START 0x01
#define OPL3_TIMER2_START 0x02
#define OPL3_CONNECTION_SELECT_REGISTER 0x04 /* Right side */
#define OPL3_RIGHT_4OP_0 0x01
#define OPL3_RIGHT_4OP_1 0x02
#define OPL3_RIGHT_4OP_2 0x04
#define OPL3_LEFT_4OP_0 0x08
#define OPL3_LEFT_4OP_1 0x10
#define OPL3_LEFT_4OP_2 0x20
#define OPL3_MODE_REGISTER 0x05 /* Right side */
#define OPL3_ENABLE 0x01
#define OPL3_OPL4_ENABLE 0x02
#define OPL3_KBD_SPLIT_REGISTER 0x08 /* Left side */
#define OPL3_COMPOSITE_SINE_WAVE_MODE 0x80 /* Don't use with OPL-3? */
#define OPL3_KEYBOARD_SPLIT 0x40
#define OPL3_PERCUSSION_REGISTER 0xbd /* Left side only */
#define OPL3_TREMOLO_DEPTH 0x80
#define OPL3_VIBRATO_DEPTH 0x40
#define OPL3_PERCUSSION_ENABLE 0x20
#define OPL3_BASSDRUM_ON 0x10
#define OPL3_SNAREDRUM_ON 0x08
#define OPL3_TOMTOM_ON 0x04
#define OPL3_CYMBAL_ON 0x02
#define OPL3_HIHAT_ON 0x01
/*
* Offsets to the register banks for operators. To get the
* register number just add the operator offset to the bank offset
*
* AM/VIB/EG/KSR/Multiple (0x20 to 0x35)
*/
#define OPL3_AM_VIB 0x20
#define OPL3_TREMOLO_ON 0x80
#define OPL3_VIBRATO_ON 0x40
#define OPL3_SUSTAIN_ON 0x20
#define OPL3_KSR 0x10 /* Key scaling rate */
#define OPL3_MULTIPLE_MASK 0x0f /* Frequency multiplier */
/*
* KSL/Total level (0x40 to 0x55)
*/
#define OPL3_KSL_LEVEL 0x40
#define OPL3_KSL_MASK 0xc0 /* Envelope scaling bits */
#define OPL3_TOTAL_LEVEL_MASK 0x3f /* Strength (volume) of OP */
/*
* Attack / Decay rate (0x60 to 0x75)
*/
#define OPL3_ATTACK_DECAY 0x60
#define OPL3_ATTACK_MASK 0xf0
#define OPL3_DECAY_MASK 0x0f
/*
* Sustain level / Release rate (0x80 to 0x95)
*/
#define OPL3_SUSTAIN_RELEASE 0x80
#define OPL3_SUSTAIN_MASK 0xf0
#define OPL3_RELEASE_MASK 0x0f
/*
* Wave select (0xE0 to 0xF5)
*/
#define OPL3_WAVE_SELECT 0xe0
/*
* Offsets to the register banks for voices. Just add to the
* voice number to get the register number.
*
* F-Number low bits (0xA0 to 0xA8).
*/
#define OPL3_FNUM_LOW 0xa0
/*
* F-number high bits / Key on / Block (octave) (0xB0 to 0xB8)
*/
#define OPL3_KEYON_BLOCK 0xb0
#define OPL3_KEYON_BIT 0x20
#define OPL3_BLOCKNUM_MASK 0x1c
#define OPL3_FNUM_HIGH_MASK 0x03
/*
* Feedback / Connection (0xc0 to 0xc8)
*
* These registers have two new bits when the OPL-3 mode
* is selected. These bits controls connecting the voice
* to the stereo channels. For 4 OP voices this bit is
* defined in the second half of the voice (add 3 to the
* register offset).
*
* For 4 OP voices the connection bit is used in the
* both halfs (gives 4 ways to connect the operators).
*/
#define OPL3_FEEDBACK_CONNECTION 0xc0
#define OPL3_FEEDBACK_MASK 0x0e /* Valid just for 1st OP of a voice */
#define OPL3_CONNECTION_BIT 0x01
#define OPL3_STEREO_BITS 0x30 /* OPL-3 only */
#define OPL3_VOICE_TO_LEFT 0x10
#define OPL3_VOICE_TO_RIGHT 0x20
#endif // opl3_reg_h__

View file

@ -1,44 +0,0 @@
/*
Copyright (C) 1994-1995 Apogee Software, Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/**********************************************************************
module: SNDCARDS.H
author: James R. Dose
date: March 31, 1994
Contains enumerated type definitions for sound cards.
(c) Copyright 1994 James R. Dose. All Rights Reserved.
**********************************************************************/
#ifndef __SNDCARDS_H
#define __SNDCARDS_H
typedef enum
{
ASS_SDL,
ASS_DirectSound,
ASS_OPL3,
ASS_WinMM,
ASS_NumSoundCards,
ASS_AutoDetect = -2
} soundcardnames;
#endif

View file

@ -1,126 +0,0 @@
/*
Copyright (C) 1994-1995 Apogee Software, Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef ___AL_MIDI_H
#define ___AL_MIDI_H
#include <inttypes.h>
#define STEREO_DETUNE 5
#define lobyte(num) ((uint32_t)*((char *)&(num)))
#define hibyte(num) ((uint32_t)*(((char *)&(num)) + 1))
#define AL_MaxVolume 127
#define AL_DefaultChannelVolume 90
#define AL_DefaultPitchBendRange 200
#define AL_VoiceNotFound -1
#define ADLIB_PORT 0x388
/* Number of slots for the voices on the chip */
#define AL_NumChipSlots 18
#define NUMADLIBVOICES 9
#define NUMADLIBCHANNELS 16
#define NOTE_ON 0x2000 /* Used to turn note on or toggle note */
#define NOTE_OFF 0x0000
#define MAX_VELOCITY 0x7f
#define MAX_OCTAVE 7
#define MAX_NOTE (MAX_OCTAVE * 12 + 11)
#define FINETUNE_MAX 31
#define FINETUNE_RANGE (FINETUNE_MAX + 1)
#define PITCHBEND_CENTER 1638400
#define MIDI_VOLUME 7
#define MIDI_PAN 10
#define MIDI_DETUNE 94
#define MIDI_ALL_NOTES_OFF 0x7B
#define MIDI_RESET_ALL_CONTROLLERS 0x79
#define MIDI_RPN_MSB 100
#define MIDI_RPN_LSB 101
#define MIDI_DATAENTRY_MSB 6
#define MIDI_DATAENTRY_LSB 38
#define MIDI_PITCHBEND_RPN 0
/* Definition of octave information to be ORed onto F-Number */
enum octaves
{
OCTAVE_0 = 0x0000,
OCTAVE_1 = 0x0400,
OCTAVE_2 = 0x0800,
OCTAVE_3 = 0x0C00,
OCTAVE_4 = 0x1000,
OCTAVE_5 = 0x1400,
OCTAVE_6 = 0x1800,
OCTAVE_7 = 0x1C00
};
typedef struct AdLibVoice
{
struct AdLibVoice *next;
struct AdLibVoice *prev;
uint32_t num;
uint32_t key;
uint32_t velocity;
uint32_t channel;
uint32_t pitchleft;
uint32_t pitchright;
int timbre;
int port;
uint32_t status;
} AdLibVoice;
typedef struct
{
AdLibVoice *start;
AdLibVoice *end;
} AdLibVoiceList;
typedef struct
{
AdLibVoiceList Voices;
int Timbre;
int Pitchbend;
int KeyOffset;
uint32_t KeyDetune;
uint32_t Volume;
uint32_t EffectiveVolume;
int Pan;
int Detune;
uint32_t RPN;
int16_t PitchBendRange;
int16_t PitchBendSemiTones;
int16_t PitchBendHundreds;
} AdLibChannel;
static int AL_Init(int rate);
static void AL_NoteOff(int channel, int key, int velocity);
static void AL_NoteOn(int channel, int key, int vel);
static void AL_ControlChange(int channel, int type, int data);
static void AL_ProgramChange(int channel, int patch);
static void AL_SetPitchBend(int channel, int lsb, int msb);
#endif

View file

@ -1,156 +0,0 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#ifndef ___MIDI_H
#define ___MIDI_H
#include "compat.h"
#define RELATIVE_BEAT(measure, beat, tick) ((tick) + ((beat) << 9) + ((measure) << 16))
//Bobby Prince thinks this may be 100
//#define GENMIDI_DefaultVolume 100
#define GENMIDI_DefaultVolume 90
#define MAX_FORMAT 1
#define NUM_MIDI_CHANNELS 16
#define TIME_PRECISION 16
#define MIDI_HEADER_SIGNATURE 0x6468544d // "MThd"
#define MIDI_TRACK_SIGNATURE 0x6b72544d // "MTrk"
#define MIDI_VOLUME 7
#define MIDI_PAN 10
#define MIDI_DETUNE 94
#define MIDI_RHYTHM_CHANNEL 9
#define MIDI_BANK_SELECT_MSB 0
#define MIDI_BANK_SELECT_LSB 32
#define MIDI_RPN_MSB 100
#define MIDI_RPN_LSB 101
#define MIDI_DATAENTRY_MSB 6
#define MIDI_DATAENTRY_LSB 38
#define MIDI_PITCHBEND_MSB 0
#define MIDI_PITCHBEND_LSB 0
#define MIDI_RUNNING_STATUS 0x80
#define MIDI_NOTE_OFF 0x8
#define MIDI_NOTE_ON 0x9
#define MIDI_POLY_AFTER_TCH 0xA
#define MIDI_CONTROL_CHANGE 0xB
#define MIDI_PROGRAM_CHANGE 0xC
#define MIDI_AFTER_TOUCH 0xD
#define MIDI_PITCH_BEND 0xE
#define MIDI_SPECIAL 0xF
#define MIDI_SYSEX 0xF0
#define MIDI_SYSEX_CONTINUE 0xF7
#define MIDI_META_EVENT 0xFF
#define MIDI_END_OF_TRACK 0x2F
#define MIDI_HOLD1 0x40
#define MIDI_SOSTENUTO 0x42
#define MIDI_TEMPO_CHANGE 0x51
#define MIDI_TIME_SIGNATURE 0x58
#define MIDI_REVERB 0x5b
#define MIDI_CHORUS 0x5d
#define MIDI_ALL_SOUNDS_OFF 0x78
#define MIDI_RESET_ALL_CONTROLLERS 0x79
#define MIDI_ALL_NOTES_OFF 0x7b
#define MIDI_MONO_MODE_ON 0x7E
#define MIDI_SYSTEM_RESET 0xFF
#define GET_NEXT_EVENT( track, data ) do { \
( data ) = *( track )->pos; \
( track )->pos += 1; \
} while (0)
#define GET_MIDI_CHANNEL( event ) ( ( event ) & 0xf )
#define GET_MIDI_COMMAND( event ) ( ( event ) >> 4 )
#define EMIDI_INFINITE -1
#define EMIDI_END_LOOP_VALUE 127
#define EMIDI_ALL_CARDS 127
#define EMIDI_INCLUDE_TRACK 110
#define EMIDI_EXCLUDE_TRACK 111
#define EMIDI_PROGRAM_CHANGE 112
#define EMIDI_VOLUME_CHANGE 113
#define EMIDI_CONTEXT_START 114
#define EMIDI_CONTEXT_END 115
#define EMIDI_LOOP_START 116
#define EMIDI_LOOP_END 117
#define EMIDI_SONG_LOOP_START 118
#define EMIDI_SONG_LOOP_END 119
#define EMIDI_GeneralMIDI 0
#define EMIDI_SoundBlaster 4
#define EMIDI_AdLib 7
#define EMIDI_AffectsCurrentCard(c, type) (((c) == EMIDI_ALL_CARDS) || ((c) == (type)))
#define EMIDI_NUM_CONTEXTS 7
typedef struct
{
char *pos;
char *loopstart;
int16_t loopcount;
int16_t RunningStatus;
unsigned time;
int FPSecondsPerTick;
int16_t tick;
int16_t beat;
int16_t measure;
int16_t BeatsPerMeasure;
int16_t TicksPerBeat;
int16_t TimeBase;
int delay;
int16_t active;
} songcontext;
typedef struct
{
char *start;
char *pos;
int delay;
int16_t active;
int16_t RunningStatus;
int16_t currentcontext;
songcontext context[EMIDI_NUM_CONTEXTS];
char EMIDI_IncludeTrack;
char EMIDI_ProgramChange;
char EMIDI_VolumeChange;
} track;
static int _MIDI_ReadNumber(void *from, size_t size);
static int _MIDI_ReadDelta(track *ptr);
static void _MIDI_ResetTracks(void);
static void _MIDI_AdvanceTick(void);
static void _MIDI_MetaEvent(track *Track);
static void _MIDI_SysEx(track *Track);
static int _MIDI_InterpretControllerInfo(track *Track, int TimeSet, int channel, int c1, int c2);
static int _MIDI_SendControlChange(int channel, int c1, int c2);
static void _MIDI_SetChannelVolume(int channel, int volume);
static void _MIDI_SendChannelVolumes(void);
static void _MIDI_InitEMIDI(void);
#endif

View file

@ -1,293 +0,0 @@
/*
Copyright (C) 1994-1995 Apogee Software, Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**********************************************************************
file: _MULTIVC.H
author: James R. Dose
date: December 20, 1993
Private header for MULTIVOC.C
(c) Copyright 1993 James R. Dose. All Rights Reserved.
**********************************************************************/
#ifndef MULTIVC_H_
#define MULTIVC_H_
#include "multivoc.h"
#define VOC_8BIT 0x0
#define VOC_16BIT 0x4
#define T_SIXTEENBIT_STEREO 0
#define T_MONO 1
#define T_16BITSOURCE 2
#define T_STEREOSOURCE 4
#define T_DEFAULT T_SIXTEENBIT_STEREO
#define MV_MAXPANPOSITION 127 /* formerly 31 */
#define MV_NUMPANPOSITIONS ( MV_MAXPANPOSITION + 1 )
#define MV_MAXTOTALVOLUME 255
#define MV_MAXVOLUME 127 /* formerly 63 */
// mirrors FX_MUSIC_PRIORITY from fx_man.h
#define MV_MUSIC_PRIORITY INT_MAX
#define MIX_VOLUME(volume) ((max(0, min((volume), 255)) * (MV_MAXVOLUME + 1)) >> 8)
extern float MV_GlobalVolume;
extern float MV_VolumeSmooth;
static FORCE_INLINE float SMOOTH_VOLUME(float const volume, float const dest)
{
return volume + (dest - volume) * MV_VolumeSmooth;
}
template <typename T>
static inline conditional_t< is_signed<T>::value, make_unsigned_t<T>, make_signed_t<T> > FLIP_SIGN(T src)
{
static constexpr make_unsigned_t<T> msb = ((make_unsigned_t<T>)1) << (sizeof(T) * CHAR_BIT - 1u);
return src ^ msb;
}
template <typename T>
static inline enable_if_t<is_signed<T>::value, T> SCALE_SAMPLE(T src, float volume)
{
return (T)Blrintf((float)src * volume);
}
template <typename T>
static inline T CONVERT_SAMPLE_FROM_SIGNED(int src);
template<>
inline int16_t CONVERT_SAMPLE_FROM_SIGNED<int16_t>(int src)
{
return src;
}
template <typename T>
static inline int CONVERT_SAMPLE_TO_SIGNED(T src);
template<>
inline int CONVERT_SAMPLE_TO_SIGNED<int16_t>(int16_t src)
{
return src;
}
template <typename S, typename D>
static inline int CONVERT_LE_SAMPLE_TO_SIGNED(S src);
template<>
inline int CONVERT_LE_SAMPLE_TO_SIGNED<uint8_t, int16_t>(uint8_t src)
{
return FLIP_SIGN(src) << 8;
}
template<>
inline int CONVERT_LE_SAMPLE_TO_SIGNED<int16_t, int16_t>(int16_t src)
{
return B_LITTLE16(src);
}
template <typename T>
static int CLAMP_SAMPLE(int src);
template<>
inline int CLAMP_SAMPLE<int16_t>(int src)
{
return clamp(src, INT16_MIN, INT16_MAX);
}
template <typename T>
static T MIX_SAMPLES(int signed_sample, T untouched_sample)
{
return CONVERT_SAMPLE_FROM_SIGNED<T>(CLAMP_SAMPLE<T>(signed_sample + CONVERT_SAMPLE_TO_SIGNED<T>(untouched_sample)));
}
struct split16_t
{
explicit split16_t(uint16_t x) : v{x} {}
uint8_t l() const
{
return (v & 0x00FFu);
}
uint8_t h() const
{
return (v & 0xFF00u) >> CHAR_BIT;
}
private:
uint16_t v;
};
#define MV_MIXBUFFERSIZE 256
#define MV_NUMBEROFBUFFERS 32
#define MV_TOTALBUFFERSIZE ( MV_MIXBUFFERSIZE * MV_NUMBEROFBUFFERS )
typedef enum : bool
{
NoMoreData,
KeepPlaying
} playbackstatus;
typedef struct VoiceNode
{
struct VoiceNode *next;
struct VoiceNode *prev;
playbackstatus (*GetSound)(struct VoiceNode *);
uint32_t (*mix)(struct VoiceNode *, uint32_t);
const char *sound;
float LeftVolume, LeftVolumeDest;
float RightVolume, RightVolumeDest;
void *rawdataptr;
const char *NextBlock;
const char *LoopStart;
const char *LoopEnd;
wavefmt_t wavetype;
char bits;
char channels;
float volume;
int LoopCount;
uint32_t LoopSize;
uint32_t BlockLength;
int ptrlength; // ptrlength-1 is the max permissible index for rawdataptr
uint32_t PitchScale;
uint32_t FixedPointBufferSize;
uint32_t length;
uint32_t SamplingRate;
uint32_t RateScale;
uint32_t position;
int Paused;
int handle;
int priority;
intptr_t callbackval;
} VoiceNode;
typedef struct
{
uint8_t left;
uint8_t right;
} Pan;
typedef struct
{
char RIFF[4];
uint32_t file_size;
char WAVE[4];
char fmt[4];
uint32_t format_size;
} riff_header;
typedef struct
{
uint16_t wFormatTag;
uint16_t nChannels;
uint32_t nSamplesPerSec;
uint32_t nAvgBytesPerSec;
uint16_t nBlockAlign;
uint16_t nBitsPerSample;
} format_header;
typedef struct
{
uint8_t DATA[4];
uint32_t size;
} data_header;
extern Pan MV_PanTable[ MV_NUMPANPOSITIONS ][ MV_MAXVOLUME + 1 ];
extern int MV_ErrorCode;
extern int MV_Installed;
extern int MV_MixRate;
extern char *MV_MusicBuffer;
extern int MV_BufferSize;
extern int MV_MIDIRenderTempo;
extern int MV_MIDIRenderTimer;
static FORCE_INLINE int MV_SetErrorCode(int status)
{
MV_ErrorCode = status;
return MV_Error;
}
void MV_PlayVoice(VoiceNode *voice);
VoiceNode *MV_AllocVoice(int priority);
void MV_SetVoiceMixMode(VoiceNode *voice);
void MV_SetVoiceVolume(VoiceNode *voice, int vol, int left, int right, float volume);
void MV_SetVoicePitch(VoiceNode *voice, uint32_t rate, int pitchoffset);
int MV_GetVorbisPosition(VoiceNode *voice);
void MV_SetVorbisPosition(VoiceNode *voice, int position);
int MV_GetFLACPosition(VoiceNode *voice);
void MV_SetFLACPosition(VoiceNode *voice, int position);
int MV_GetXAPosition(VoiceNode *voice);
void MV_SetXAPosition(VoiceNode *voice, int position);
int MV_GetXMPPosition(VoiceNode *voice);
void MV_SetXMPPosition(VoiceNode *voice, int position);
void MV_ReleaseVorbisVoice(VoiceNode *voice);
void MV_ReleaseZMusicVoice(VoiceNode* voice);
void MV_ReleaseFLACVoice(VoiceNode *voice);
void MV_ReleaseXAVoice(VoiceNode *voice);
void MV_ReleaseXMPVoice(VoiceNode *voice);
// implemented in mix.c
template <typename S, typename D> uint32_t MV_MixMono(struct VoiceNode * const voice, uint32_t length);
template <typename S, typename D> uint32_t MV_MixStereo(struct VoiceNode * const voice, uint32_t length);
template <typename T> void MV_Reverb(char const *src, char * const dest, const float volume, int count);
// implemented in mixst.c
template <typename S, typename D> uint32_t MV_MixMonoStereo(struct VoiceNode * const voice, uint32_t length);
template <typename S, typename D> uint32_t MV_MixStereoStereo(struct VoiceNode * const voice, uint32_t length);
extern char *MV_MixDestination; // pointer to the next output sample
extern int MV_SampleSize;
extern int MV_RightChannelOffset;
#define loopStartTagCount 3
extern const char *loopStartTags[loopStartTagCount];
#define loopEndTagCount 2
extern const char *loopEndTags[loopEndTagCount];
#define loopLengthTagCount 2
extern const char *loopLengthTags[loopLengthTagCount];
#if defined __POWERPC__ || defined GEKKO
# define BIGENDIAN
#endif
#endif

View file

@ -1,776 +0,0 @@
/*
Copyright (C) 1994-1995 Apogee Software, Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/**********************************************************************
module: AL_MIDI.C
author: James R. Dose
date: April 1, 1994
Low level routines to support General MIDI music on AdLib compatible
cards.
(c) Copyright 1994 James R. Dose. All Rights Reserved.
**********************************************************************/
#include "driver_adlib.h"
#include "_al_midi.h"
#include "_multivc.h"
#include "compat.h"
#include "midi.h"
#include "midifuncs.h"
#include "opl3.h"
#include "opl3_reg.h"
#include "c_cvars.h"
CUSTOM_CVARD(Bool, mus_al_stereo, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG, "enable/disable OPL3 stereo mode")
{
AL_Stereo = self;
AL_SetStereo(AL_Stereo);
}
CVARD(Bool, mus_al_additivemode, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG, "enable/disable alternate additive AdLib timbre mode")
enum
{
AdLibErr_Warning = -2,
AdLibErr_Error = -1,
AdLibErr_Ok = 0,
};
static void AL_Shutdown(void);
static int ErrorCode;
int AdLibDrv_GetError(void) { return ErrorCode; }
const char *AdLibDrv_ErrorString(int const ErrorNumber)
{
const char *ErrorString;
switch( ErrorNumber )
{
case AdLibErr_Warning :
case AdLibErr_Error :
ErrorString = AdLibDrv_ErrorString( ErrorCode );
break;
case AdLibErr_Ok :
ErrorString = "AdLib ok.";
break;
default:
ErrorString = "Unknown AdLib error.";
break;
}
return ErrorString;
}
int AdLibDrv_MIDI_Init(midifuncs * const funcs)
{
AdLibDrv_MIDI_Shutdown();
Bmemset(funcs, 0, sizeof(midifuncs));
funcs->NoteOff = AL_NoteOff;
funcs->NoteOn = AL_NoteOn;
funcs->PolyAftertouch = nullptr;
funcs->ControlChange = AL_ControlChange;
funcs->ProgramChange = AL_ProgramChange;
funcs->ChannelAftertouch = nullptr;
funcs->PitchBend = AL_SetPitchBend;
return AdLibErr_Ok;
}
void AdLibDrv_MIDI_HaltPlayback(void) { MV_UnhookMusicRoutine(); }
void AdLibDrv_MIDI_Shutdown(void)
{
AdLibDrv_MIDI_HaltPlayback();
AL_Shutdown();
}
int AdLibDrv_MIDI_StartPlayback(void (*service)(void))
{
AdLibDrv_MIDI_HaltPlayback();
AL_Init(MV_MixRate);
MV_HookMusicRoutine(service);
return MIDI_Ok;
}
void AdLibDrv_MIDI_SetTempo(int const tempo, int const division)
{
MV_MIDIRenderTempo = tempo * division / 60;
MV_MIDIRenderTimer = 0;
}
static opl3_chip chip;
opl3_chip *AL_GetChip(void) { return &chip; }
static uint32_t constexpr OctavePitch[MAX_OCTAVE+1] = {
OCTAVE_0, OCTAVE_1, OCTAVE_2, OCTAVE_3, OCTAVE_4, OCTAVE_5, OCTAVE_6, OCTAVE_7,
};
static uint32_t NoteMod12[MAX_NOTE+1];
static uint32_t NoteDiv12[MAX_NOTE+1];
// Pitch table
//static unsigned NotePitch[ FINETUNE_MAX+1 ][ 12 ] =
// {
// { C, C_SHARP, D, D_SHARP, E, F, F_SHARP, G, G_SHARP, A, A_SHARP, B },
// };
static uint32_t constexpr NotePitch[FINETUNE_MAX+1][12] = {
{ 0x157, 0x16b, 0x181, 0x198, 0x1b0, 0x1ca, 0x1e5, 0x202, 0x220, 0x241, 0x263, 0x287 },
{ 0x157, 0x16b, 0x181, 0x198, 0x1b0, 0x1ca, 0x1e5, 0x202, 0x220, 0x242, 0x264, 0x288 },
{ 0x158, 0x16c, 0x182, 0x199, 0x1b1, 0x1cb, 0x1e6, 0x203, 0x221, 0x243, 0x265, 0x289 },
{ 0x158, 0x16c, 0x183, 0x19a, 0x1b2, 0x1cc, 0x1e7, 0x204, 0x222, 0x244, 0x266, 0x28a },
{ 0x159, 0x16d, 0x183, 0x19a, 0x1b3, 0x1cd, 0x1e8, 0x205, 0x223, 0x245, 0x267, 0x28b },
{ 0x15a, 0x16e, 0x184, 0x19b, 0x1b3, 0x1ce, 0x1e9, 0x206, 0x224, 0x246, 0x268, 0x28c },
{ 0x15a, 0x16e, 0x185, 0x19c, 0x1b4, 0x1ce, 0x1ea, 0x207, 0x225, 0x247, 0x269, 0x28e },
{ 0x15b, 0x16f, 0x185, 0x19d, 0x1b5, 0x1cf, 0x1eb, 0x208, 0x226, 0x248, 0x26a, 0x28f },
{ 0x15b, 0x170, 0x186, 0x19d, 0x1b6, 0x1d0, 0x1ec, 0x209, 0x227, 0x249, 0x26b, 0x290 },
{ 0x15c, 0x170, 0x187, 0x19e, 0x1b7, 0x1d1, 0x1ec, 0x20a, 0x228, 0x24a, 0x26d, 0x291 },
{ 0x15d, 0x171, 0x188, 0x19f, 0x1b7, 0x1d2, 0x1ed, 0x20b, 0x229, 0x24b, 0x26e, 0x292 },
{ 0x15d, 0x172, 0x188, 0x1a0, 0x1b8, 0x1d3, 0x1ee, 0x20c, 0x22a, 0x24c, 0x26f, 0x293 },
{ 0x15e, 0x172, 0x189, 0x1a0, 0x1b9, 0x1d4, 0x1ef, 0x20d, 0x22b, 0x24d, 0x270, 0x295 },
{ 0x15f, 0x173, 0x18a, 0x1a1, 0x1ba, 0x1d4, 0x1f0, 0x20e, 0x22c, 0x24e, 0x271, 0x296 },
{ 0x15f, 0x174, 0x18a, 0x1a2, 0x1bb, 0x1d5, 0x1f1, 0x20f, 0x22d, 0x24f, 0x272, 0x297 },
{ 0x160, 0x174, 0x18b, 0x1a3, 0x1bb, 0x1d6, 0x1f2, 0x210, 0x22e, 0x250, 0x273, 0x298 },
{ 0x161, 0x175, 0x18c, 0x1a3, 0x1bc, 0x1d7, 0x1f3, 0x211, 0x22f, 0x251, 0x274, 0x299 },
{ 0x161, 0x176, 0x18c, 0x1a4, 0x1bd, 0x1d8, 0x1f4, 0x212, 0x230, 0x252, 0x276, 0x29b },
{ 0x162, 0x176, 0x18d, 0x1a5, 0x1be, 0x1d9, 0x1f5, 0x212, 0x231, 0x254, 0x277, 0x29c },
{ 0x162, 0x177, 0x18e, 0x1a6, 0x1bf, 0x1d9, 0x1f5, 0x213, 0x232, 0x255, 0x278, 0x29d },
{ 0x163, 0x178, 0x18f, 0x1a6, 0x1bf, 0x1da, 0x1f6, 0x214, 0x233, 0x256, 0x279, 0x29e },
{ 0x164, 0x179, 0x18f, 0x1a7, 0x1c0, 0x1db, 0x1f7, 0x215, 0x235, 0x257, 0x27a, 0x29f },
{ 0x164, 0x179, 0x190, 0x1a8, 0x1c1, 0x1dc, 0x1f8, 0x216, 0x236, 0x258, 0x27b, 0x2a1 },
{ 0x165, 0x17a, 0x191, 0x1a9, 0x1c2, 0x1dd, 0x1f9, 0x217, 0x237, 0x259, 0x27c, 0x2a2 },
{ 0x166, 0x17b, 0x192, 0x1aa, 0x1c3, 0x1de, 0x1fa, 0x218, 0x238, 0x25a, 0x27e, 0x2a3 },
{ 0x166, 0x17b, 0x192, 0x1aa, 0x1c3, 0x1df, 0x1fb, 0x219, 0x239, 0x25b, 0x27f, 0x2a4 },
{ 0x167, 0x17c, 0x193, 0x1ab, 0x1c4, 0x1e0, 0x1fc, 0x21a, 0x23a, 0x25c, 0x280, 0x2a6 },
{ 0x168, 0x17d, 0x194, 0x1ac, 0x1c5, 0x1e0, 0x1fd, 0x21b, 0x23b, 0x25d, 0x281, 0x2a7 },
{ 0x168, 0x17d, 0x194, 0x1ad, 0x1c6, 0x1e1, 0x1fe, 0x21c, 0x23c, 0x25e, 0x282, 0x2a8 },
{ 0x169, 0x17e, 0x195, 0x1ad, 0x1c7, 0x1e2, 0x1ff, 0x21d, 0x23d, 0x260, 0x283, 0x2a9 },
{ 0x16a, 0x17f, 0x196, 0x1ae, 0x1c8, 0x1e3, 0x1ff, 0x21e, 0x23e, 0x261, 0x284, 0x2ab },
{ 0x16a, 0x17f, 0x197, 0x1af, 0x1c8, 0x1e4, 0x200, 0x21f, 0x23f, 0x262, 0x286, 0x2ac }
};
// Slot numbers as a function of the voice and the operator.
// ( melodic only)
static int constexpr slotVoice[NUMADLIBVOICES][2] = {
{ 0, 3 }, // voice 0
{ 1, 4 }, // 1
{ 2, 5 }, // 2
{ 6, 9 }, // 3
{ 7, 10 }, // 4
{ 8, 11 }, // 5
{ 12, 15 }, // 6
{ 13, 16 }, // 7
{ 14, 17 }, // 8
};
static int VoiceLevel[AL_NumChipSlots][2];
static int VoiceKsl[AL_NumChipSlots][2];
// This table gives the offset of each slot within the chip.
// offset = fn( slot)
static int8_t constexpr offsetSlot[AL_NumChipSlots] = { 0, 1, 2, 3, 4, 5, 8, 9, 10, 11, 12, 13, 16, 17, 18, 19, 20, 21 };
static int VoiceReserved[NUMADLIBVOICES * 2];
static AdLibVoice Voice[NUMADLIBVOICES * 2];
static AdLibVoiceList Voice_Pool;
static AdLibChannel Channel[NUMADLIBCHANNELS];
static int constexpr AL_LeftPort = ADLIB_PORT;
static int constexpr AL_RightPort = ADLIB_PORT + 2;
static int constexpr AL_MaxMidiChannel = ARRAY_SIZE(Channel);
int AL_Stereo = TRUE;
int AL_PostAmp = 3;
// TODO: clean up this shit...
#define OFFSET(structure, offset) (*((char **)&(structure)[offset]))
#define LL_AddToTail(type, listhead, node) \
LL_AddNode((char *)(node), (char **)&((listhead)->end), (char **)&((listhead)->start), (intptr_t) & ((type *)0)->prev, \
(intptr_t) & ((type *)0)->next)
#define LL_Remove(type, listhead, node) \
LL_RemoveNode((char *)(node), (char **)&((listhead)->start), (char **)&((listhead)->end), (intptr_t) & ((type *)0)->next, \
(intptr_t) & ((type *)0)->prev)
static void LL_RemoveNode(char *item, char **head, char **tail, intptr_t next, intptr_t prev)
{
if (OFFSET(item, prev) == nullptr)
*head = OFFSET(item, next);
else
OFFSET(OFFSET(item, prev), next) = OFFSET(item, next);
if (OFFSET(item, next) == nullptr)
*tail = OFFSET(item, prev);
else
OFFSET(OFFSET(item, next), prev) = OFFSET(item, prev);
OFFSET(item, next) = nullptr;
OFFSET(item, prev) = nullptr;
}
static void LL_AddNode(char *item, char **head, char **tail, intptr_t next, intptr_t prev)
{
OFFSET(item, prev) = nullptr;
OFFSET(item, next) = *head;
if (*head)
OFFSET(*head, prev) = item;
else
*tail = item;
*head = item;
}
static void AL_SendOutputToPort(int const port, int const reg, int const data)
{
OPL3_WriteRegBuffered(&chip, (Bit16u)(reg + ((port & 2) << 7)), (Bit8u)data);
}
static void AL_SendOutput(int const voice, int const reg, int const data)
{
AL_SendOutputToPort(voice ? AL_LeftPort : AL_RightPort, reg, data);
}
static void AL_SetVoiceTimbre(int const voice)
{
int const channel = Voice[voice].channel;
int const patch = (channel == 9) ? Voice[voice].key + 128 : Channel[channel].Timbre;
if (Voice[voice].timbre == patch)
return;
Voice[voice].timbre = patch;
auto const timbre = &ADLIB_TimbreBank[patch];
int const port = Voice[voice].port;
int const voc = (voice >= NUMADLIBVOICES) ? voice - NUMADLIBVOICES : voice;
int slot = slotVoice[voc][0];
int off = offsetSlot[slot];
VoiceLevel[slot][port] = OPL3_TOTAL_LEVEL_MASK - (timbre->Level[0] & OPL3_TOTAL_LEVEL_MASK);
VoiceKsl[slot][port] = timbre->Level[0] & OPL3_KSL_MASK;
AL_SendOutput(port, OPL3_FNUM_LOW + voc, 0);
AL_SendOutput(port, OPL3_KEYON_BLOCK + voc, 0);
// Let voice clear the release
AL_SendOutput(port, OPL3_SUSTAIN_RELEASE + off, 0xff);
AL_SendOutput(port, OPL3_ATTACK_DECAY + off, timbre->Env1[0]);
AL_SendOutput(port, OPL3_SUSTAIN_RELEASE + off, timbre->Env2[0]);
AL_SendOutput(port, OPL3_ENABLE_WAVE_SELECT + off, timbre->SAVEK[0]);
AL_SendOutput(port, OPL3_WAVE_SELECT + off, timbre->Wave[0]);
AL_SendOutput(port, OPL3_KSL_LEVEL + off, timbre->Level[0]);
slot = slotVoice[voc][1];
AL_SendOutput(port, OPL3_FEEDBACK_CONNECTION + voc, (timbre->Feedback & OPL3_FEEDBACK_MASK) | OPL3_STEREO_BITS);
off = offsetSlot[slot];
VoiceLevel[slot][port] = OPL3_TOTAL_LEVEL_MASK - (timbre->Level[1] & OPL3_TOTAL_LEVEL_MASK);
VoiceKsl[slot][port] = timbre->Level[1] & OPL3_KSL_MASK;
AL_SendOutput(port, OPL3_KSL_LEVEL + off, OPL3_TOTAL_LEVEL_MASK);
// Let voice clear the release
AL_SendOutput(port, OPL3_SUSTAIN_RELEASE + off, 0xff);
AL_SendOutput(port, OPL3_ATTACK_DECAY + off, timbre->Env1[1]);
AL_SendOutput(port, OPL3_SUSTAIN_RELEASE + off, timbre->Env2[1]);
AL_SendOutput(port, OPL3_ENABLE_WAVE_SELECT + off, timbre->SAVEK[1]);
AL_SendOutput(port, OPL3_WAVE_SELECT + off, timbre->Wave[1]);
}
static void AL_SetVoiceVolume(int const voice)
{
int const channel = Voice[voice].channel;
auto const timbre = &ADLIB_TimbreBank[Voice[voice].timbre];
int const velocity = min<int>(Voice[voice].velocity + timbre->Velocity, MAX_VELOCITY);
int const voc = (voice >= NUMADLIBVOICES) ? voice - NUMADLIBVOICES : voice;
int const slot = slotVoice[voc][1];
int const port = Voice[voice].port;
// amplitude
auto t1 = (uint32_t)VoiceLevel[slot][port] * (velocity + 0x80);
t1 = (Channel[channel].Volume * t1) >> 15;
uint32_t volume = t1 ^ OPL3_TOTAL_LEVEL_MASK;
volume |= (uint32_t)VoiceKsl[slot][port];
AL_SendOutput(port, OPL3_KSL_LEVEL + offsetSlot[slot], volume);
// Check if this timbre is Additive
if (timbre->Feedback & 0x01)
{
int const slot = slotVoice[voc][0];
uint32_t t2;
// amplitude
if (mus_al_additivemode)
t1 = (uint32_t)VoiceLevel[slot][port] * (velocity + 0x80);
t2 = (Channel[channel].Volume * t1) >> 15;
volume = t2 ^ OPL3_TOTAL_LEVEL_MASK;
volume |= (uint32_t)VoiceKsl[slot][port];
AL_SendOutput(port, OPL3_KSL_LEVEL + offsetSlot[slot], volume);
}
}
static int AL_AllocVoice(void)
{
if (!Voice_Pool.start)
return AL_VoiceNotFound;
int const voice = Voice_Pool.start->num;
LL_Remove(AdLibVoice, &Voice_Pool, &Voice[voice]);
return voice;
}
static int AL_GetVoice(int const channel, int const key)
{
auto const *voice = Channel[channel].Voices.start;
while (voice != nullptr)
{
if (voice->key == (uint32_t)key)
return voice->num;
voice = voice->next;
}
return AL_VoiceNotFound;
}
static void AL_SetVoicePitch(int const voice)
{
int const port = Voice[voice].port;
int const voc = (voice >= NUMADLIBVOICES) ? voice - NUMADLIBVOICES : voice;
int const channel = Voice[voice].channel;
int patch, note;
if (channel == 9)
{
patch = Voice[voice].key + 128;
note = ADLIB_TimbreBank[patch].Transpose;
}
else
{
patch = Channel[channel].Timbre;
note = Voice[voice].key + ADLIB_TimbreBank[patch].Transpose;
}
note += Channel[channel].KeyOffset - 12;
note = clamp(note, 0, MAX_NOTE);
int detune = Channel[channel].KeyDetune;
int ScaleNote = NoteMod12[note];
int Octave = NoteDiv12[note];
int pitch = OctavePitch[Octave] | NotePitch[detune][ScaleNote];
Voice[voice].pitchleft = pitch;
pitch |= Voice[voice].status;
AL_SendOutput(port, OPL3_FNUM_LOW + voc, pitch);
AL_SendOutput(port, OPL3_KEYON_BLOCK + voc, pitch >> 8);
}
static void AL_SetVoicePan(int const voice)
{
int const port = Voice[voice].port;
int const voc = (voice >= NUMADLIBVOICES) ? voice - NUMADLIBVOICES : voice;
int const channel = Voice[voice].channel;
if (AL_Stereo)
AL_SendOutput(port, 0xD0 + voc, Channel[channel].Pan << 1);
}
static void AL_SetChannelVolume(int const channel, int const volume)
{
Channel[channel].Volume = clamp(volume, 0, AL_MaxVolume);
auto voice = Channel[channel].Voices.start;
while (voice != nullptr)
{
AL_SetVoiceVolume(voice->num);
voice = voice->next;
}
}
static void AL_SetChannelPan(int const channel, int const pan)
{
// Don't pan drum sounds
if (channel != 9)
Channel[channel].Pan = pan;
auto voice = Channel[channel].Voices.start;
while (voice != nullptr)
{
AL_SetVoicePan(voice->num);
voice = voice->next;
}
}
static void AL_SetChannelDetune(int const channel, int const detune) { Channel[channel].Detune = detune; }
static void AL_ResetVoices(void)
{
Voice_Pool.start = nullptr;
Voice_Pool.end = nullptr;
int const numvoices = NUMADLIBVOICES * 2;
for (int index = 0; index < numvoices; index++)
{
if (VoiceReserved[index] == FALSE)
{
Voice[index].num = index;
Voice[index].key = 0;
Voice[index].velocity = 0;
Voice[index].channel = -1;
Voice[index].timbre = -1;
Voice[index].port = (index < NUMADLIBVOICES) ? 0 : 1;
Voice[index].status = NOTE_OFF;
LL_AddToTail(AdLibVoice, &Voice_Pool, &Voice[index]);
}
}
for (int index = 0; index < NUMADLIBCHANNELS; index++)
{
Channel[index] = {};
Channel[index].Volume = AL_DefaultChannelVolume;
Channel[index].Pan = 64;
Channel[index].PitchBendRange = AL_DefaultPitchBendRange;
Channel[index].PitchBendSemiTones = AL_DefaultPitchBendRange / 100;
Channel[index].PitchBendHundreds = AL_DefaultPitchBendRange % 100;
}
}
static void AL_CalcPitchInfo(void)
{
// int finetune;
// double detune;
for (int note = 0; note <= MAX_NOTE; note++)
{
NoteMod12[note] = note % 12;
NoteDiv12[note] = note / 12;
}
// for( finetune = 1; finetune <= FINETUNE_MAX; finetune++ )
// {
// detune = pow( 2, ( double )finetune / ( 12.0 * FINETUNE_RANGE ) );
// for( note = 0; note < 12; note++ )
// {
// NotePitch[ finetune ][ note ] = ( ( double )NotePitch[ 0 ][ note ] * detune );
// }
// }
}
static void AL_FlushCard(int const port)
{
for (int i = 0; i < NUMADLIBVOICES; i++)
{
if (VoiceReserved[i])
continue;
auto slot1 = offsetSlot[slotVoice[i][0]];
auto slot2 = offsetSlot[slotVoice[i][1]];
AL_SendOutputToPort(port, OPL3_FNUM_LOW + i, 0);
AL_SendOutputToPort(port, OPL3_KEYON_BLOCK + i, 0);
AL_SendOutputToPort(port, OPL3_WAVE_SELECT + slot1, 0);
AL_SendOutputToPort(port, OPL3_WAVE_SELECT + slot2, 0);
// Set the envelope to be fast and quiet
AL_SendOutputToPort(port, OPL3_ATTACK_DECAY + slot1, 0xff);
AL_SendOutputToPort(port, OPL3_ATTACK_DECAY + slot2, 0xff);
AL_SendOutputToPort(port, OPL3_SUSTAIN_RELEASE + slot1, 0xff);
AL_SendOutputToPort(port, OPL3_SUSTAIN_RELEASE + slot2, 0xff);
// Maximum attenuation
AL_SendOutputToPort(port, OPL3_KSL_LEVEL + slot1, 0xff);
AL_SendOutputToPort(port, OPL3_KSL_LEVEL + slot2, 0xff);
}
}
static void AL_Reset(void)
{
AL_SendOutputToPort(ADLIB_PORT, 1, OPL3_ENABLE_WAVE_SELECT);
AL_SendOutputToPort(ADLIB_PORT, OPL3_KBD_SPLIT_REGISTER, 0);
// Set the values: AM Depth, VIB depth & Rhythm
AL_SendOutputToPort(ADLIB_PORT, OPL3_PERCUSSION_REGISTER, 0);
AL_SetStereo(AL_Stereo);
AL_FlushCard(AL_LeftPort);
AL_FlushCard(AL_RightPort);
}
void AL_SetStereo(int const stereo) { AL_SendOutputToPort(AL_RightPort, OPL3_MODE_REGISTER, (stereo << 1) + 1); }
static void AL_NoteOff(int const channel, int const key, int velocity)
{
UNREFERENCED_PARAMETER(velocity);
// We only play channels 1 through 10
if (channel > AL_MaxMidiChannel)
return;
int const voice = AL_GetVoice(channel, key);
if (voice == AL_VoiceNotFound)
return;
Voice[voice].status = NOTE_OFF;
int const port = Voice[voice].port;
int const voc = (voice >= NUMADLIBVOICES) ? voice - NUMADLIBVOICES : voice;
AL_SendOutput(port, OPL3_KEYON_BLOCK + voc, hibyte(Voice[voice].pitchleft));
LL_Remove(AdLibVoice, &Channel[channel].Voices, &Voice[voice]);
LL_AddToTail(AdLibVoice, &Voice_Pool, &Voice[voice]);
}
static void AL_NoteOn(int const channel, int const key, int const velocity)
{
// We only play channels 1 through 10
if (channel > AL_MaxMidiChannel)
return;
if (velocity == 0)
{
AL_NoteOff(channel, key, velocity);
return;
}
int voice = AL_AllocVoice();
if (voice == AL_VoiceNotFound)
{
if (Channel[9].Voices.start)
{
AL_NoteOff(9, Channel[9].Voices.start->key, 0);
voice = AL_AllocVoice();
}
if (voice == AL_VoiceNotFound)
return;
}
Voice[voice].key = key;
Voice[voice].channel = channel;
Voice[voice].velocity = velocity;
Voice[voice].status = NOTE_ON;
LL_AddToTail(AdLibVoice, &Channel[channel].Voices, &Voice[voice]);
AL_SetVoiceTimbre(voice);
AL_SetVoiceVolume(voice);
AL_SetVoicePitch(voice);
AL_SetVoicePan(voice);
}
static inline void AL_AllNotesOff(int const channel)
{
while (Channel[channel].Voices.start != nullptr)
AL_NoteOff(channel, Channel[channel].Voices.start->key, 0);
}
static void AL_ControlChange(int const channel, int const type, int const data)
{
// We only play channels 1 through 10
if (channel > AL_MaxMidiChannel)
return;
switch (type)
{
case MIDI_VOLUME:
AL_SetChannelVolume(channel, data);
break;
case MIDI_PAN:
AL_SetChannelPan(channel, data);
break;
case MIDI_DETUNE:
AL_SetChannelDetune(channel, data);
break;
case MIDI_ALL_NOTES_OFF:
AL_AllNotesOff(channel);
break;
case MIDI_RESET_ALL_CONTROLLERS:
AL_ResetVoices();
AL_SetChannelVolume(channel, AL_DefaultChannelVolume);
AL_SetChannelPan(channel, 64);
AL_SetChannelDetune(channel, 0);
break;
case MIDI_RPN_MSB:
Channel[channel].RPN &= 0x00FF;
Channel[channel].RPN |= (data & 0xFF) << 8;
break;
case MIDI_RPN_LSB:
Channel[channel].RPN &= 0xFF00;
Channel[channel].RPN |= data & 0xFF;
break;
case MIDI_DATAENTRY_MSB:
if (Channel[channel].RPN == MIDI_PITCHBEND_RPN)
{
Channel[channel].PitchBendSemiTones = data;
Channel[channel].PitchBendRange = Channel[channel].PitchBendSemiTones * 100 + Channel[channel].PitchBendHundreds;
}
break;
case MIDI_DATAENTRY_LSB:
if (Channel[channel].RPN == MIDI_PITCHBEND_RPN)
{
Channel[channel].PitchBendHundreds = data;
Channel[channel].PitchBendRange = Channel[channel].PitchBendSemiTones * 100 + Channel[channel].PitchBendHundreds;
}
break;
}
}
static void AL_ProgramChange(int const channel, int const patch)
{
// We only play channels 1 through 10
if (channel > AL_MaxMidiChannel)
return;
Channel[channel].Timbre = patch;
}
static void AL_SetPitchBend(int const channel, int const lsb, int const msb)
{
// We only play channels 1 through 10
if (channel > AL_MaxMidiChannel)
return;
int const pitchbend = lsb + (msb << 8);
int const TotalBend = pitchbend * Channel[channel].PitchBendRange / (PITCHBEND_CENTER / FINETUNE_RANGE);
Channel[channel].Pitchbend = pitchbend;
Channel[channel].KeyOffset = (int)(TotalBend / FINETUNE_RANGE);
Channel[channel].KeyOffset -= Channel[channel].PitchBendSemiTones;
Channel[channel].KeyDetune = (uint32_t)(TotalBend % FINETUNE_RANGE);
auto voice = Channel[channel].Voices.start;
while (voice != nullptr)
{
AL_SetVoicePitch(voice->num);
voice = voice->next;
}
}
static void AL_Shutdown(void)
{
AL_ResetVoices();
AL_Reset();
}
static int AL_Init(int const rate)
{
OPL3_Reset(&chip, rate);
AL_CalcPitchInfo();
AL_Reset();
AL_ResetVoices();
return AdLibErr_Ok;
}
void AL_RegisterTimbreBank(uint8_t const *timbres)
{
for (int i = 0; i < 256; i++)
{
ADLIB_TimbreBank[i].SAVEK[0] = *(timbres++);
ADLIB_TimbreBank[i].SAVEK[1] = *(timbres++);
ADLIB_TimbreBank[i].Level[0] = *(timbres++);
ADLIB_TimbreBank[i].Level[1] = *(timbres++);
ADLIB_TimbreBank[i].Env1[0] = *(timbres++);
ADLIB_TimbreBank[i].Env1[1] = *(timbres++);
ADLIB_TimbreBank[i].Env2[0] = *(timbres++);
ADLIB_TimbreBank[i].Env2[1] = *(timbres++);
ADLIB_TimbreBank[i].Wave[0] = *(timbres++);
ADLIB_TimbreBank[i].Wave[1] = *(timbres++);
ADLIB_TimbreBank[i].Feedback = *(timbres++);
ADLIB_TimbreBank[i].Transpose = *(int8_t *)(timbres++);
ADLIB_TimbreBank[i].Velocity = *(int8_t *)(timbres++);
}
}

View file

@ -1,36 +0,0 @@
/*
Copyright (C) 2009 Jonathon Fowler <jf@jonof.id.au>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "al_midi.h"
#include "midifuncs.h"
#include "opl3.h"
extern int AL_Stereo;
extern int AL_PostAmp;
int AdLibDrv_GetError(void);
const char *AdLibDrv_ErrorString(int ErrorNumber);
int AdLibDrv_MIDI_Init(midifuncs *);
void AdLibDrv_MIDI_Shutdown(void);
int AdLibDrv_MIDI_StartPlayback(void (*service)(void));
void AdLibDrv_MIDI_HaltPlayback(void);
void AdLibDrv_MIDI_SetTempo(int tempo, int division);

View file

@ -1,422 +0,0 @@
/*
Copyright (C) 2009 Jonathon Fowler <jf@jonof.id.au>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* DirectSound output driver for MultiVoc
*/
#define NEED_MMSYSTEM_H
#define NEED_DSOUND_H
#include "driver_directsound.h"
#include "compat.h"
#include "multivoc.h"
#include "mutex.h"
#include "windows_inc.h"
#define MIXBUFFERPOSITIONS 8
static int ErrorCode;
static int Initialised;
static int Playing;
static char * MixBuffer;
static int MixBufferSize;
static int MixBufferCount;
static int MixBufferCurrent;
static int MixBufferUsed;
static void (*MixCallBack)(void);
static LPDIRECTSOUND lpds;
static LPDIRECTSOUNDBUFFER lpdsbprimary, lpdsbsec;
static LPDIRECTSOUNDNOTIFY lpdsnotify;
static HANDLE mixThread;
static mutex_t mutex;
static DSBPOSITIONNOTIFY notifyPositions[MIXBUFFERPOSITIONS + 1] = {};
static void FillBufferPosition(char * ptr, int remaining)
{
int len = 0;
do
{
if (MixBufferUsed == MixBufferSize)
{
MixCallBack();
MixBufferUsed = 0;
if (++MixBufferCurrent >= MixBufferCount)
MixBufferCurrent -= MixBufferCount;
}
do
{
char *sptr = MixBuffer + (MixBufferCurrent * MixBufferSize) + MixBufferUsed;
len = MixBufferSize - MixBufferUsed;
if (remaining < len)
len = remaining;
memcpy(ptr, sptr, len);
ptr += len;
MixBufferUsed += len;
remaining -= len;
}
while (remaining >= len && MixBufferUsed < MixBufferSize);
}
while (remaining >= len);
}
static void FillBuffer(int bufnum)
{
LPVOID ptr, ptr2;
DWORD remaining, remaining2;
int retries = 1;
do
{
HRESULT err = IDirectSoundBuffer_Lock(lpdsbsec, notifyPositions[bufnum].dwOffset, notifyPositions[1].dwOffset,
&ptr, &remaining, &ptr2, &remaining2, 0);
if (EDUKE32_PREDICT_FALSE(FAILED(err)))
{
if (err == DSERR_BUFFERLOST)
{
if (FAILED(err = IDirectSoundBuffer_Restore(lpdsbsec)))
goto fail;
if (retries-- > 0)
continue;
}
fail:
MV_Printf("DirectSound FillBuffer: err %x\n", (uint32_t)err);
return;
}
break;
}
while (1);
if (ptr && remaining)
FillBufferPosition((char *)ptr, remaining);
if (ptr2 && remaining2)
FillBufferPosition((char *)ptr2, remaining2);
IDirectSoundBuffer_Unlock(lpdsbsec, ptr, remaining, ptr2, remaining2);
}
static DWORD WINAPI fillDataThread(LPVOID lpParameter)
{
UNREFERENCED_PARAMETER(lpParameter);
HANDLE handles[MIXBUFFERPOSITIONS+1];
for (int i = 0; i < ARRAY_SSIZE(handles); i++)
handles[i] = notifyPositions[i].hEventNotify;
do
{
DWORD const waitret = WaitForMultipleObjects(MIXBUFFERPOSITIONS, handles, FALSE, INFINITE);
if (waitret >= WAIT_OBJECT_0 && waitret < WAIT_OBJECT_0+MIXBUFFERPOSITIONS)
{
mutex_lock(&mutex);
FillBuffer((waitret + MIXBUFFERPOSITIONS - 1 - WAIT_OBJECT_0) % MIXBUFFERPOSITIONS);
mutex_unlock(&mutex);
}
else
{
switch (waitret)
{
case WAIT_OBJECT_0 + MIXBUFFERPOSITIONS:
ExitThread(0);
break;
default:
MV_Printf("DirectSound fillDataThread: wfmo err %d\n", (int)waitret);
break;
}
}
}
while (1);
return 0;
}
static void TeardownDSound(HRESULT err)
{
if (FAILED(err))
MV_Printf("Dying error: %x\n", (uint32_t)err);
if (lpdsnotify)
IDirectSoundNotify_Release(lpdsnotify), lpdsnotify = nullptr;
for (int i = 0; i < MIXBUFFERPOSITIONS + 1; i++)
{
if (notifyPositions[i].hEventNotify)
CloseHandle(notifyPositions[i].hEventNotify);
notifyPositions[i].hEventNotify = 0;
}
#ifdef RENDERTYPEWIN
if (mutex)
CloseHandle(mutex), mutex = nullptr;
#endif
if (lpdsbsec)
IDirectSoundBuffer_Release(lpdsbsec), lpdsbsec = nullptr;
if (lpdsbprimary)
IDirectSoundBuffer_Release(lpdsbprimary), lpdsbprimary = nullptr;
if (lpds)
IDirectSound_Release(lpds), lpds = nullptr;
}
static int DirectSound_Error(HRESULT err, int code)
{
TeardownDSound(err);
ErrorCode = code;
return DSErr_Error;
}
int DirectSoundDrv_PCM_Init(int *mixrate, int *numchannels, void * initdata)
{
HRESULT err;
DSBUFFERDESC bufdesc = {};
WAVEFORMATEX wfex = {};
if (Initialised)
DirectSoundDrv_PCM_Shutdown();
if (FAILED(err = DirectSoundCreate(0, &lpds, 0)))
return DirectSound_Error(err, DSErr_DirectSoundCreate);
if (FAILED(err = IDirectSound_SetCooperativeLevel(lpds, (HWND) initdata, DSSCL_PRIORITY)))
return DirectSound_Error(err, DSErr_SetCooperativeLevel);
bufdesc.dwSize = sizeof(DSBUFFERDESC);
bufdesc.dwFlags = DSBCAPS_LOCSOFTWARE | DSBCAPS_PRIMARYBUFFER | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STICKYFOCUS;
if (FAILED(err = IDirectSound_CreateSoundBuffer(lpds, &bufdesc, &lpdsbprimary, 0)))
return DirectSound_Error(err, DSErr_CreateSoundBuffer);
wfex.wFormatTag = WAVE_FORMAT_PCM;
wfex.nChannels = *numchannels;
wfex.nSamplesPerSec = *mixrate;
wfex.wBitsPerSample = 16;
wfex.nBlockAlign = wfex.nChannels * wfex.wBitsPerSample / 8;
wfex.nAvgBytesPerSec = wfex.nSamplesPerSec * wfex.nBlockAlign;
if (FAILED(err = IDirectSoundBuffer_SetFormat(lpdsbprimary, &wfex)))
return DirectSound_Error(err, DSErr_SetFormat);
bufdesc.dwFlags = DSBCAPS_LOCSOFTWARE | DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STICKYFOCUS;
bufdesc.dwBufferBytes = wfex.nBlockAlign * 2048 * 2;
bufdesc.lpwfxFormat = &wfex;
if (FAILED(err = IDirectSound_CreateSoundBuffer(lpds, &bufdesc, &lpdsbsec, 0)))
return DirectSound_Error(err, DSErr_CreateSoundBufferSecondary);
if (FAILED(err = IDirectSoundBuffer_QueryInterface(lpdsbsec, IID_IDirectSoundNotify, (LPVOID *)&lpdsnotify)))
return DirectSound_Error(err, DSErr_Notify);
for (int i = 0; i < MIXBUFFERPOSITIONS; i++)
{
notifyPositions[i].dwOffset = (bufdesc.dwBufferBytes/MIXBUFFERPOSITIONS)*i;
notifyPositions[i].hEventNotify = CreateEvent(nullptr, FALSE, FALSE, nullptr);
if (!notifyPositions[i].hEventNotify)
return DirectSound_Error(DS_OK, DSErr_NotifyEvents);
}
notifyPositions[MIXBUFFERPOSITIONS].dwOffset = DSBPN_OFFSETSTOP;
notifyPositions[MIXBUFFERPOSITIONS].hEventNotify = CreateEvent(nullptr, FALSE, FALSE, nullptr);
if (FAILED(err = IDirectSoundNotify_SetNotificationPositions(lpdsnotify, MIXBUFFERPOSITIONS+1, notifyPositions)))
return DirectSound_Error(err, DSErr_SetNotificationPositions);
if (FAILED(err = IDirectSoundBuffer_Play(lpdsbprimary, 0, 0, DSBPLAY_LOOPING)))
return DirectSound_Error(err, DSErr_Play);
Initialised = 1;
return DSErr_Ok;
}
void DirectSoundDrv_PCM_Shutdown(void)
{
if (!Initialised)
return;
DirectSoundDrv_PCM_StopPlayback();
TeardownDSound(DS_OK);
Initialised = 0;
}
int DirectSoundDrv_PCM_BeginPlayback(char *BufferStart, int BufferSize, int NumDivisions, void (*CallBackFunc)(void))
{
if (!Initialised)
{
ErrorCode = DSErr_Uninitialised;
return DSErr_Error;
}
DirectSoundDrv_PCM_StopPlayback();
MixBuffer = BufferStart;
MixBufferSize = BufferSize;
MixBufferCount = NumDivisions;
MixBufferCurrent = 0;
MixBufferUsed = 0;
MixCallBack = CallBackFunc;
// prime the buffer
FillBuffer(0);
if ((mixThread = CreateThread(nullptr, 0, fillDataThread, 0, 0, 0)) == nullptr)
{
ErrorCode = DSErr_CreateThread;
return DSErr_Error;
}
SetThreadPriority(mixThread, THREAD_PRIORITY_ABOVE_NORMAL);
HRESULT err = IDirectSoundBuffer_Play(lpdsbsec, 0, 0, DSBPLAY_LOOPING);
if (FAILED(err))
{
ErrorCode = DSErr_PlaySecondary;
return DSErr_Error;
}
Playing = 1;
return DSErr_Ok;
}
void DirectSoundDrv_PCM_StopPlayback(void)
{
if (!Playing)
return;
IDirectSoundBuffer_Stop(lpdsbsec);
IDirectSoundBuffer_SetCurrentPosition(lpdsbsec, 0);
Playing = 0;
}
void DirectSoundDrv_PCM_Lock(void)
{
mutex_lock(&mutex);
}
void DirectSoundDrv_PCM_Unlock(void)
{
mutex_unlock(&mutex);
}
int DirectSoundDrv_GetError(void)
{
return ErrorCode;
}
const char *DirectSoundDrv_ErrorString(int ErrorNumber)
{
const char *ErrorString;
switch (ErrorNumber)
{
case DSErr_Warning:
case DSErr_Error:
ErrorString = DirectSoundDrv_ErrorString(ErrorCode);
break;
case DSErr_Ok:
ErrorString = "DirectSound ok.";
break;
case DSErr_Uninitialised:
ErrorString = "DirectSound uninitialised.";
break;
case DSErr_DirectSoundCreate:
ErrorString = "DirectSound error: DirectSoundCreate failed.";
break;
case DSErr_SetCooperativeLevel:
ErrorString = "DirectSound error: SetCooperativeLevel failed.";
break;
case DSErr_CreateSoundBuffer:
ErrorString = "DirectSound error: primary CreateSoundBuffer failed.";
break;
case DSErr_CreateSoundBufferSecondary:
ErrorString = "DirectSound error: secondary CreateSoundBuffer failed.";
break;
case DSErr_SetFormat:
ErrorString = "DirectSound error: primary buffer SetFormat failed.";
break;
case DSErr_SetFormatSecondary:
ErrorString = "DirectSound error: secondary buffer SetFormat failed.";
break;
case DSErr_Notify:
ErrorString = "DirectSound error: failed querying secondary buffer for notify interface.";
break;
case DSErr_NotifyEvents:
ErrorString = "DirectSound error: failed creating notify events.";
break;
case DSErr_SetNotificationPositions:
ErrorString = "DirectSound error: failed setting notification positions.";
break;
case DSErr_Play:
ErrorString = "DirectSound error: primary buffer Play failed.";
break;
case DSErr_PlaySecondary:
ErrorString = "DirectSound error: secondary buffer Play failed.";
break;
case DSErr_CreateThread:
ErrorString = "DirectSound error: failed creating mix thread.";
break;
default:
ErrorString = "Unknown DirectSound error code.";
break;
}
return ErrorString;
}

View file

@ -1,51 +0,0 @@
/*
Copyright (C) 2009 Jonathon Fowler <jf@jonof.id.au>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <inttypes.h>
enum
{
DSErr_Warning = -2,
DSErr_Error = -1,
DSErr_Ok = 0,
DSErr_Uninitialised,
DSErr_DirectSoundCreate,
DSErr_SetCooperativeLevel,
DSErr_CreateSoundBuffer,
DSErr_CreateSoundBufferSecondary,
DSErr_SetFormat,
DSErr_SetFormatSecondary,
DSErr_Notify,
DSErr_NotifyEvents,
DSErr_SetNotificationPositions,
DSErr_Play,
DSErr_PlaySecondary,
DSErr_CreateThread,
};
int DirectSoundDrv_GetError(void);
const char *DirectSoundDrv_ErrorString(int ErrorNumber);
int DirectSoundDrv_PCM_Init(int *mixrate, int *numchannels, void *initdata);
void DirectSoundDrv_PCM_Shutdown(void);
int DirectSoundDrv_PCM_BeginPlayback(char *BufferStart, int BufferSize, int NumDivisions, void (*CallBackFunc)(void));
void DirectSoundDrv_PCM_StopPlayback(void);
void DirectSoundDrv_PCM_Lock(void);
void DirectSoundDrv_PCM_Unlock(void);

View file

@ -1,319 +0,0 @@
/*
Copyright (C) 2009 Jonathon Fowler <jf@jonof.id.au>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* libSDL output driver for MultiVoc
*/
#include "driver_sdl.h"
#include "compat.h"
#include "multivoc.h"
#include "mutex.h"
#include "sdl_inc.h"
enum {
SDLErr_Warning = -2,
SDLErr_Error = -1,
SDLErr_Ok = 0,
SDLErr_Uninitialised,
SDLErr_InitSubSystem,
SDLErr_OpenAudio
};
static int ErrorCode = SDLErr_Ok;
static int Initialised;
static int Playing;
static uint32_t StartedSDL;
static char *MixBuffer;
static int MixBufferSize;
static int MixBufferCount;
static int MixBufferCurrent;
static int MixBufferUsed;
static void (*MixCallBack)(void);
#if (SDL_MAJOR_VERSION == 2)
static SDL_AudioDeviceID audio_dev;
#endif
static void fillData(void * userdata, Uint8 * ptr, int remaining)
{
if (!MixBuffer || !MixCallBack)
return;
UNREFERENCED_PARAMETER(userdata);
int len;
char *sptr;
while (remaining > 0) {
if (MixBufferUsed == MixBufferSize) {
MixCallBack();
MixBufferUsed = 0;
MixBufferCurrent++;
if (MixBufferCurrent >= MixBufferCount) {
MixBufferCurrent -= MixBufferCount;
}
}
while (remaining > 0 && MixBufferUsed < MixBufferSize) {
sptr = MixBuffer + (MixBufferCurrent * MixBufferSize) + MixBufferUsed;
len = MixBufferSize - MixBufferUsed;
if (remaining < len) {
len = remaining;
}
memcpy(ptr, sptr, len);
ptr += len;
MixBufferUsed += len;
remaining -= len;
}
}
}
int SDLDrv_GetError(void)
{
return ErrorCode;
}
const char *SDLDrv_ErrorString(int ErrorNumber)
{
const char *ErrorString;
switch( ErrorNumber ) {
case SDLErr_Warning :
case SDLErr_Error :
ErrorString = SDLDrv_ErrorString( ErrorCode );
break;
case SDLErr_Ok :
ErrorString = "SDL Audio ok.";
break;
case SDLErr_Uninitialised:
ErrorString = "SDL Audio uninitialised.";
break;
case SDLErr_InitSubSystem:
ErrorString = "SDL Audio: error in Init or InitSubSystem.";
break;
case SDLErr_OpenAudio:
ErrorString = "SDL Audio: error in OpenAudio.";
break;
default:
ErrorString = "Unknown SDL Audio error code.";
break;
}
return ErrorString;
}
int SDLDrv_PCM_Init(int *mixrate, int *numchannels, void * initdata)
{
UNREFERENCED_PARAMETER(initdata);
Uint32 inited;
int err = 0;
SDL_AudioSpec spec, actual;
if (Initialised) {
SDLDrv_PCM_Shutdown();
}
inited = SDL_WasInit(SDL_INIT_AUDIO);
if (!(inited & SDL_INIT_AUDIO)) {
err = SDL_InitSubSystem(SDL_INIT_AUDIO);
StartedSDL = SDL_WasInit(SDL_INIT_AUDIO);
}
if (err < 0) {
ErrorCode = SDLErr_InitSubSystem;
return SDLErr_Error;
}
int chunksize = 512;
#ifdef __ANDROID__
chunksize = droidinfo.audio_buffer_size;
#endif
spec.freq = *mixrate;
spec.format = AUDIO_S16SYS;
spec.channels = *numchannels;
spec.samples = chunksize;
spec.callback = fillData;
spec.userdata = nullptr;
Bmemset(&actual, 0, sizeof(actual));
#if (SDL_MAJOR_VERSION == 1)
err = !SDL_OpenAudio(&spec, &actual);
#else
audio_dev = err = SDL_OpenAudioDevice(nullptr, 0, &spec, &actual, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE);
#endif
if (err == 0) {
ErrorCode = SDLErr_OpenAudio;
return SDLErr_Error;
}
#if (SDL_MAJOR_VERSION == 1)
char drivername[64] = "(error)";
SDL_AudioDriverName(drivername, sizeof(drivername));
MV_Printf("SDL %s driver\n", drivername);
#else
auto drivername = Xstrdup(SDL_GetCurrentAudioDriver());
for (int i=0;drivername[i] != 0;++i)
drivername[i] = toupper(drivername[i]);
auto devname = Xstrdup(SDL_GetAudioDeviceName(0, 0));
auto pdevname = Bstrchr(devname, '(');
if (pdevname)
{
auto rt = Bstrchr(pdevname++, ')');
if (rt != nullptr) *rt = '\0';
}
else
pdevname = devname;
MV_Printf("SDL %s driver on %s\n", drivername, pdevname);
Xfree(devname);
Xfree(drivername);
#endif
#if (SDL_MAJOR_VERSION == 1)
if (actual.freq == 0 || actual.channels == 0) {
// hack for when SDL said it opened the audio, but clearly didn't
SDL_CloseAudio();
ErrorCode = SDLErr_OpenAudio;
return SDLErr_Error;
}
#endif
err = 0;
*mixrate = actual.freq;
if (actual.format == AUDIO_U8 || actual.format == AUDIO_S8)
{
ErrorCode = SDLErr_OpenAudio;
err = 1;
}
*numchannels = actual.channels;
if (actual.channels != 1 && actual.channels != 2)
{
ErrorCode = SDLErr_OpenAudio;
err = 1;
}
if (err)
{
SDL_CloseAudio();
return SDLErr_Error;
}
Initialised = 1;
return SDLErr_Ok;
}
void SDLDrv_PCM_Shutdown(void)
{
if (!Initialised)
return;
if (StartedSDL)
SDL_QuitSubSystem(StartedSDL);
StartedSDL = 0;
Initialised = 0;
}
int SDLDrv_PCM_BeginPlayback(char *BufferStart, int BufferSize,
int NumDivisions, void ( *CallBackFunc )( void ) )
{
if (!Initialised) {
ErrorCode = SDLErr_Uninitialised;
return SDLErr_Error;
}
if (Playing) {
SDLDrv_PCM_StopPlayback();
}
MixBuffer = BufferStart;
MixBufferSize = BufferSize;
MixBufferCount = NumDivisions;
MixBufferCurrent = 0;
MixBufferUsed = 0;
MixCallBack = CallBackFunc;
// prime the buffer
MixCallBack();
#if (SDL_MAJOR_VERSION == 2)
SDL_PauseAudioDevice(audio_dev, 0);
#else
SDL_PauseAudio(0);
#endif
Playing = 1;
return SDLErr_Ok;
}
void SDLDrv_PCM_StopPlayback(void)
{
if (!Initialised || !Playing) {
return;
}
#if (SDL_MAJOR_VERSION == 2)
SDL_PauseAudioDevice(audio_dev, 1);
#else
SDL_PauseAudio(1);
#endif
Playing = 0;
}
void SDLDrv_PCM_Lock(void)
{
#if (SDL_MAJOR_VERSION == 2)
SDL_LockAudioDevice(audio_dev);
#else
SDL_LockAudio();
#endif
}
void SDLDrv_PCM_Unlock(void)
{
#if (SDL_MAJOR_VERSION == 2)
SDL_UnlockAudioDevice(audio_dev);
#else
SDL_UnlockAudio();
#endif
}

View file

@ -1,35 +0,0 @@
/*
Copyright (C) 2009 Jonathon Fowler <jf@jonof.id.au>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef driver_sdl_h__
#define driver_sdl_h__
#include "compat.h"
int SDLDrv_GetError(void);
const char *SDLDrv_ErrorString( int ErrorNumber );
int SDLDrv_PCM_Init(int *mixrate, int *numchannels, void * initdata);
void SDLDrv_PCM_Shutdown(void);
int SDLDrv_PCM_BeginPlayback(char *BufferStart, int BufferSize,
int NumDivisions, void ( *CallBackFunc )( void ) );
void SDLDrv_PCM_StopPlayback(void);
void SDLDrv_PCM_Lock(void);
void SDLDrv_PCM_Unlock(void);
#endif // driver_sdl_h__

View file

@ -1,838 +0,0 @@
/*
Copyright (C) 2009 Jonathon Fowler <jf@jonof.id.au>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/**
* WinMM MIDI output driver
*/
#include "driver_winmm.h"
#include "compat.h"
#include "ll.h"
#include "midifuncs.h"
#include "multivoc.h"
#include <mmsystem.h>
#ifdef _MSC_VER
#define inline _inline
#endif
enum
{
WinMMErr_Warning = -2,
WinMMErr_Error = -1,
WinMMErr_Ok = 0,
WinMMErr_Uninitialised,
WinMMErr_NotifyWindow,
WinMMErr_MIDIStreamOpen,
WinMMErr_MIDIStreamRestart,
WinMMErr_MIDICreateEvent,
WinMMErr_MIDIPlayThread,
WinMMErr_MIDICreateMutex
};
static int ErrorCode = WinMMErr_Ok;
static BOOL midiInstalled;
static HMIDISTRM midiStream;
static UINT midiDeviceID = MIDI_MAPPER;
static void (*midiThreadService)(void);
static uint32_t midiThreadTimer;
static uint32_t midiLastEventTime;
static uint32_t midiThreadQueueTimer;
static uint32_t midiThreadQueueTicks;
static HANDLE midiThread;
static HANDLE midiThreadQuitEvent;
static HANDLE midiMutex;
static BOOL midiStreamRunning;
static int midiLastDivision;
#define THREAD_QUEUE_INTERVAL 10 // 1/10 sec
#define MIDI_BUFFER_SPACE (12*128u) // 128 note-on events
typedef struct MidiBuffer {
struct MidiBuffer *next;
struct MidiBuffer *prev;
BOOL prepared;
MIDIHDR hdr;
} MidiBuffer;
static volatile MidiBuffer activeMidiBuffers;
static volatile MidiBuffer spareMidiBuffers;
static MidiBuffer *currentMidiBuffer;
#define MIDI_NOTE_OFF 0x80
#define MIDI_NOTE_ON 0x90
#define MIDI_POLY_AFTER_TCH 0xA0
#define MIDI_CONTROL_CHANGE 0xB0
#define MIDI_PROGRAM_CHANGE 0xC0
#define MIDI_AFTER_TOUCH 0xD0
#define MIDI_PITCH_BEND 0xE0
#define MIDI_META_EVENT 0xFF
#define MIDI_END_OF_TRACK 0x2F
#define MIDI_TEMPO_CHANGE 0x51
#define MIDI_MONO_MODE_ON 0x7E
#define MIDI_ALL_NOTES_OFF 0x7B
int WinMMDrv_GetError(void)
{
return ErrorCode;
}
const char *WinMMDrv_ErrorString( int ErrorNumber )
{
const char *ErrorString;
switch( ErrorNumber )
{
case WinMMErr_Warning :
case WinMMErr_Error :
ErrorString = WinMMDrv_ErrorString( ErrorCode );
break;
case WinMMErr_Ok :
ErrorString = "WinMM ok.";
break;
case WinMMErr_Uninitialised:
ErrorString = "WinMM uninitialised.";
break;
case WinMMErr_MIDIStreamOpen:
ErrorString = "MIDI error: failed opening stream.";
break;
case WinMMErr_MIDIStreamRestart:
ErrorString = "MIDI error: failed starting stream.";
break;
case WinMMErr_MIDICreateEvent:
ErrorString = "MIDI error: failed creating play thread quit event.";
break;
case WinMMErr_MIDIPlayThread:
ErrorString = "MIDI error: failed creating play thread.";
break;
case WinMMErr_MIDICreateMutex:
ErrorString = "MIDI error: failed creating play mutex.";
break;
default:
ErrorString = "Unknown WinMM error code.";
break;
}
return ErrorString;
}
// will append "err nnn (ssss)\n" to the end of the string it emits
static void midi_error(MMRESULT rv, const char * fmt, ...)
{
va_list va;
const char * errtxt = "?";
switch (rv) {
case MMSYSERR_NOERROR: errtxt = "MMSYSERR_NOERROR"; break;
case MMSYSERR_BADDEVICEID: errtxt = "MMSYSERR_BADDEVICEID"; break;
case MMSYSERR_NOTENABLED: errtxt = "MMSYSERR_NOTENABLED"; break;
case MMSYSERR_ALLOCATED: errtxt = "MMSYSERR_ALLOCATED"; break;
case MMSYSERR_INVALHANDLE: errtxt = "MMSYSERR_INVALHANDLE"; break;
case MMSYSERR_NODRIVER: errtxt = "MMSYSERR_NODRIVER"; break;
case MMSYSERR_NOMEM: errtxt = "MMSYSERR_NOMEM"; break;
case MMSYSERR_NOTSUPPORTED: errtxt = "MMSYSERR_NOTSUPPORTED"; break;
case MMSYSERR_BADERRNUM: errtxt = "MMSYSERR_BADERRNUM"; break;
case MMSYSERR_INVALFLAG: errtxt = "MMSYSERR_INVALFLAG"; break;
case MMSYSERR_INVALPARAM: errtxt = "MMSYSERR_INVALPARAM"; break;
case MMSYSERR_HANDLEBUSY: errtxt = "MMSYSERR_HANDLEBUSY"; break;
case MMSYSERR_INVALIDALIAS: errtxt = "MMSYSERR_INVALIDALIAS"; break;
case MMSYSERR_BADDB: errtxt = "MMSYSERR_BADDB"; break;
case MMSYSERR_KEYNOTFOUND: errtxt = "MMSYSERR_KEYNOTFOUND"; break;
case MMSYSERR_READERROR: errtxt = "MMSYSERR_READERROR"; break;
case MMSYSERR_WRITEERROR: errtxt = "MMSYSERR_WRITEERROR"; break;
case MMSYSERR_DELETEERROR: errtxt = "MMSYSERR_DELETEERROR"; break;
case MMSYSERR_VALNOTFOUND: errtxt = "MMSYSERR_VALNOTFOUND"; break;
case MMSYSERR_NODRIVERCB: errtxt = "MMSYSERR_NODRIVERCB"; break;
default: break;
}
va_start(va, fmt);
MV_Printf(fmt, va);
va_end(va);
MV_Printf(" err %d (%s)\n", (int)rv, errtxt);
}
static void midi_dispose_buffer(MidiBuffer * node, const char * caller)
{
MMRESULT rv;
if (node->prepared) {
rv = midiOutUnprepareHeader( (HMIDIOUT) midiStream, &node->hdr, sizeof(MIDIHDR) );
if (rv != MMSYSERR_NOERROR) {
midi_error(rv, "WinMM %s/midi_dispose_buffer midiOutUnprepareHeader", caller);
}
node->prepared = FALSE;
}
if (midiThread) {
// remove the node from the activeMidiBuffers list
LL_Remove( node, next, prev );
// when playing, we keep the buffers
LL_Add( (MidiBuffer*) &spareMidiBuffers, node, next, prev );
//MV_Printf("WinMM %s/midi_dispose_buffer recycling buffer %p\n", caller, node);
} else {
// when not, we throw them away
free(node);
//MV_Printf("WinMM %s/midi_dispose_buffer freeing buffer %p\n", caller, node);
}
}
static void midi_gc_buffers(void)
{
MidiBuffer *node, *next;
for ( node = activeMidiBuffers.next; node != &activeMidiBuffers; node = next ) {
next = node->next;
if (node->hdr.dwFlags & MHDR_DONE) {
midi_dispose_buffer(node, "midi_gc_buffers");
}
}
}
static void midi_free_buffers(void)
{
MidiBuffer *node, *next;
//MV_Printf("waiting for active buffers to return\n");
while (!LL_ListEmpty(&activeMidiBuffers, next, prev)) {
// wait for Windows to finish with all the buffers queued
midi_gc_buffers();
//MV_Printf("waiting...\n");
Sleep(10);
}
//MV_Printf("waiting over\n");
for ( node = spareMidiBuffers.next; node != &spareMidiBuffers; node = next ) {
next = node->next;
LL_Remove( node, next, prev );
free(node);
//MV_Printf("WinMM midi_free_buffers freeing buffer %p\n", node);
}
assert(currentMidiBuffer == 0);
}
static void midi_flush_current_buffer(void)
{
MMRESULT rv;
MIDIEVENT * evt;
BOOL needsPrepare = FALSE;
if (!currentMidiBuffer) {
return;
}
evt = (MIDIEVENT *) currentMidiBuffer->hdr.lpData;
if (!midiThread) {
// immediate messages don't use a MIDIEVENT header so strip it off and
// make some adjustments
currentMidiBuffer->hdr.dwBufferLength = currentMidiBuffer->hdr.dwBytesRecorded - 12;
currentMidiBuffer->hdr.dwBytesRecorded = 0;
currentMidiBuffer->hdr.lpData = (LPSTR) &evt->dwParms[0];
if (currentMidiBuffer->hdr.dwBufferLength > 0) {
needsPrepare = TRUE;
}
} else {
needsPrepare = TRUE;
}
if (needsPrepare) {
// playing a file, or sending a sysex when not playing means
// we need to prepare the buffer
rv = midiOutPrepareHeader( (HMIDIOUT) midiStream, &currentMidiBuffer->hdr, sizeof(MIDIHDR) );
if (rv != MMSYSERR_NOERROR) {
midi_error(rv, "WinMM midi_flush_current_buffer midiOutPrepareHeader");
return;
}
currentMidiBuffer->prepared = TRUE;
}
if (midiThread) {
// midi file playing, so send events to the stream
LL_Add( (MidiBuffer*) &activeMidiBuffers, currentMidiBuffer, next, prev );
rv = midiStreamOut(midiStream, &currentMidiBuffer->hdr, sizeof(MIDIHDR));
if (rv != MMSYSERR_NOERROR) {
midi_error(rv, "WinMM midi_flush_current_buffer midiStreamOut");
midi_dispose_buffer(currentMidiBuffer, "midi_flush_current_buffer");
return;
}
//MV_Printf("WinMM midi_flush_current_buffer queued buffer %p\n", currentMidiBuffer);
} else {
// midi file not playing, so send immediately
if (currentMidiBuffer->hdr.dwBufferLength > 0) {
rv = midiOutLongMsg( (HMIDIOUT) midiStream, &currentMidiBuffer->hdr, sizeof(MIDIHDR) );
if (rv == MMSYSERR_NOERROR) {
// busy-wait for Windows to be done with it
while (!(currentMidiBuffer->hdr.dwFlags & MHDR_DONE)) ;
//MV_Printf("WinMM midi_flush_current_buffer sent immediate long\n");
} else {
midi_error(rv, "WinMM midi_flush_current_buffer midiOutLongMsg");
}
} else {
rv = midiOutShortMsg( (HMIDIOUT) midiStream, evt->dwEvent );
if (rv == MMSYSERR_NOERROR) {
//MV_Printf("WinMM midi_flush_current_buffer sent immediate short\n");
} else {
midi_error(rv, "WinMM midi_flush_current_buffer midiOutShortMsg");
}
}
midi_dispose_buffer(currentMidiBuffer, "midi_flush_current_buffer");
}
currentMidiBuffer = 0;
}
static void midi_setup_event(int length, unsigned char ** data)
{
MIDIEVENT * evt;
evt = (MIDIEVENT *) ((intptr_t) currentMidiBuffer->hdr.lpData +
currentMidiBuffer->hdr.dwBytesRecorded);
evt->dwDeltaTime = midiThread ? (midiThreadTimer - midiLastEventTime) : 0;
evt->dwStreamID = 0;
if (length <= 3) {
evt->dwEvent = (DWORD)MEVT_SHORTMSG << 24;
*data = (unsigned char *) &evt->dwEvent;
} else {
evt->dwEvent = ((DWORD)MEVT_LONGMSG << 24) | (length & 0x00ffffff);
*data = (unsigned char *) &evt->dwParms[0];
}
}
/* Gets space in the buffer presently being filled.
If insufficient space can be found in the buffer,
what is there is flushed to the stream and a new
buffer large enough is allocated.
Returns a pointer to starting writing at in 'data'.
*/
static BOOL midi_get_buffer(int length, unsigned char ** data)
{
uint32_t datalen;
MidiBuffer * node;
// determine the space to alloc.
// the size of a MIDIEVENT is 3*sizeof(DWORD) = 12.
// short messages need only that amount of space.
// long messages need additional space equal to the length of
// the message, padded to 4 bytes
if (length <= 3) {
datalen = 12;
} else {
datalen = 12 + length;
if ((datalen & 3) > 0) {
datalen += 4 - (datalen & 3);
}
}
if (!midiThread) {
assert(currentMidiBuffer == 0);
}
if (currentMidiBuffer && (currentMidiBuffer->hdr.dwBufferLength -
currentMidiBuffer->hdr.dwBytesRecorded) >= datalen) {
// there was enough space in the current buffer, so hand that back
midi_setup_event(length, data);
currentMidiBuffer->hdr.dwBytesRecorded += datalen;
return TRUE;
}
if (currentMidiBuffer) {
// not enough space in the current buffer to accommodate the
// new data, so flush it to the stream
midi_flush_current_buffer();
currentMidiBuffer = 0;
}
// check if there's a spare buffer big enough to hold the message
if (midiThread) {
for ( node = spareMidiBuffers.next; node != &spareMidiBuffers; node = node->next ) {
if (node->hdr.dwBufferLength >= datalen) {
// yes!
LL_Remove( node, next, prev );
node->hdr.dwBytesRecorded = 0;
memset(node->hdr.lpData, 0, node->hdr.dwBufferLength);
currentMidiBuffer = node;
//MV_Printf("WinMM midi_get_buffer fetched buffer %p\n", node);
break;
}
}
}
if (!currentMidiBuffer) {
// there were no spare buffers, or none were big enough, so
// allocate a new one
int size;
if (midiThread) {
// playing a file, so allocate a buffer for more than
// one event
size = max(MIDI_BUFFER_SPACE, datalen);
} else {
// not playing a file, so allocate just a buffer for
// the event we'll be sending immediately
size = datalen;
}
node = (MidiBuffer *) malloc( sizeof(MidiBuffer) + size );
if (node == 0) {
return FALSE;
}
memset(node, 0, sizeof(MidiBuffer) + datalen);
node->hdr.dwUser = (DWORD_PTR) node;
node->hdr.lpData = (LPSTR) ((intptr_t)node + sizeof(MidiBuffer));
node->hdr.dwBufferLength = size;
node->hdr.dwBytesRecorded = 0;
currentMidiBuffer = node;
//MV_Printf("WinMM midi_get_buffer allocated buffer %p\n", node);
}
midi_setup_event(length, data);
currentMidiBuffer->hdr.dwBytesRecorded += datalen;
return TRUE;
}
static inline void midi_sequence_event(void)
{
if (!midiThread) {
// a midi event being sent out of playback (streaming) mode
midi_flush_current_buffer();
return;
}
//MV_Printf("WinMM midi_sequence_event buffered\n");
// update the delta time counter
midiLastEventTime = midiThreadTimer;
}
static void Func_NoteOff( int channel, int key, int velocity )
{
unsigned char * data;
if (midi_get_buffer(3, &data)) {
data[0] = MIDI_NOTE_OFF | channel;
data[1] = key;
data[2] = velocity;
midi_sequence_event();
} else MV_Printf("WinMM Func_NoteOff error\n");
}
static void Func_NoteOn( int channel, int key, int velocity )
{
unsigned char * data;
if (midi_get_buffer(3, &data)) {
data[0] = MIDI_NOTE_ON | channel;
data[1] = key;
data[2] = velocity;
midi_sequence_event();
} else MV_Printf("WinMM Func_NoteOn error\n");
}
static void Func_PolyAftertouch( int channel, int key, int pressure )
{
unsigned char * data;
if (midi_get_buffer(3, &data)) {
data[0] = MIDI_POLY_AFTER_TCH | channel;
data[1] = key;
data[2] = pressure;
midi_sequence_event();
} else MV_Printf("WinMM Func_PolyAftertouch error\n");
}
static void Func_ControlChange( int channel, int number, int value )
{
unsigned char * data;
if (midi_get_buffer(3, &data)) {
data[0] = MIDI_CONTROL_CHANGE | channel;
data[1] = number;
data[2] = value;
midi_sequence_event();
} else MV_Printf("WinMM Func_ControlChange error\n");
}
static void Func_ProgramChange( int channel, int program )
{
unsigned char * data;
if (midi_get_buffer(2, &data)) {
data[0] = MIDI_PROGRAM_CHANGE | channel;
data[1] = program;
midi_sequence_event();
} else MV_Printf("WinMM Func_ProgramChange error\n");
}
static void Func_ChannelAftertouch( int channel, int pressure )
{
unsigned char * data;
if (midi_get_buffer(2, &data)) {
data[0] = MIDI_AFTER_TOUCH | channel;
data[1] = pressure;
midi_sequence_event();
} else MV_Printf("WinMM Func_ChannelAftertouch error\n");
}
static void Func_PitchBend( int channel, int lsb, int msb )
{
unsigned char * data;
if (midi_get_buffer(3, &data)) {
data[0] = MIDI_PITCH_BEND | channel;
data[1] = lsb;
data[2] = msb;
midi_sequence_event();
} else MV_Printf("WinMM Func_PitchBend error\n");
}
static void Func_SysEx( const unsigned char * data, int length )
{
unsigned char * wdata;
if (midi_get_buffer(length, &wdata)) {
memcpy(wdata, data, length);
midi_sequence_event();
} else MV_Printf("WinMM Func_SysEx error\n");
}
int WinMMDrv_MIDI_Init(midifuncs * funcs)
{
MMRESULT rv;
if (midiInstalled) {
WinMMDrv_MIDI_Shutdown();
}
memset(funcs, 0, sizeof(midifuncs));
LL_Reset( (MidiBuffer*) &activeMidiBuffers, next, prev );
LL_Reset( (MidiBuffer*) &spareMidiBuffers, next, prev );
midiMutex = CreateMutex(0, FALSE, 0);
if (!midiMutex) {
ErrorCode = WinMMErr_MIDICreateMutex;
return WinMMErr_Error;
}
rv = midiStreamOpen(&midiStream, &midiDeviceID, 1, (DWORD_PTR) 0, (DWORD_PTR) 0, CALLBACK_NULL);
if (rv != MMSYSERR_NOERROR) {
CloseHandle(midiMutex);
midiMutex = 0;
midi_error(rv, "WinMM MIDI_Init midiStreamOpen");
ErrorCode = WinMMErr_MIDIStreamOpen;
return WinMMErr_Error;
}
funcs->NoteOff = Func_NoteOff;
funcs->NoteOn = Func_NoteOn;
funcs->PolyAftertouch = Func_PolyAftertouch;
funcs->ControlChange = Func_ControlChange;
funcs->ProgramChange = Func_ProgramChange;
funcs->ChannelAftertouch = Func_ChannelAftertouch;
funcs->PitchBend = Func_PitchBend;
funcs->SysEx = Func_SysEx;
midiInstalled = TRUE;
return WinMMErr_Ok;
}
void WinMMDrv_MIDI_Shutdown(void)
{
MMRESULT rv;
if (!midiInstalled) {
return;
}
WinMMDrv_MIDI_HaltPlayback();
if (midiStream) {
rv = midiStreamClose(midiStream);
if (rv != MMSYSERR_NOERROR) {
midi_error(rv, "WinMM MIDI_Shutdown midiStreamClose");
}
}
if (midiMutex) {
CloseHandle(midiMutex);
}
midiStream = 0;
midiMutex = 0;
midiInstalled = FALSE;
}
static DWORD midi_get_tick(void)
{
MMRESULT rv;
MMTIME mmtime;
mmtime.wType = TIME_TICKS;
rv = midiStreamPosition(midiStream, &mmtime, sizeof(MMTIME));
if (rv != MMSYSERR_NOERROR) {
midi_error(rv, "WinMM midi_get_tick midiStreamPosition");
return 0;
}
return mmtime.u.ticks;
}
static DWORD WINAPI midiDataThread(LPVOID lpParameter)
{
UNREFERENCED_PARAMETER(lpParameter);
DWORD waitret;
DWORD sequenceTime;
DWORD sleepAmount = 100 / THREAD_QUEUE_INTERVAL;
// MV_Printf("WinMM midiDataThread: started\n");
midiThreadTimer = midi_get_tick();
midiLastEventTime = midiThreadTimer;
midiThreadQueueTimer = midiThreadTimer + midiThreadQueueTicks;
WinMMDrv_MIDI_Lock();
midi_gc_buffers();
while (midiThreadTimer < midiThreadQueueTimer) {
if (midiThreadService) {
midiThreadService();
}
midiThreadTimer++;
}
midi_flush_current_buffer();
WinMMDrv_MIDI_Unlock();
do {
waitret = WaitForSingleObject(midiThreadQuitEvent, sleepAmount);
if (waitret == WAIT_OBJECT_0) {
// MV_Printf("WinMM midiDataThread: exiting\n");
break;
} else if (waitret == WAIT_TIMEOUT) {
// queue a tick
sequenceTime = midi_get_tick();
sleepAmount = 100 / THREAD_QUEUE_INTERVAL;
if ((midiThreadTimer - sequenceTime) > midiThreadQueueTicks) {
// we're running ahead, so sleep for half the usual
// amount and try again
sleepAmount /= 2;
continue;
}
midiThreadQueueTimer = sequenceTime + midiThreadQueueTicks;
WinMMDrv_MIDI_Lock();
midi_gc_buffers();
while (midiThreadTimer < midiThreadQueueTimer) {
if (midiThreadService) {
midiThreadService();
}
midiThreadTimer++;
}
midi_flush_current_buffer();
WinMMDrv_MIDI_Unlock();
} else {
MV_Printf("WinMM midiDataThread: wfmo err %d\n", (int) waitret);
}
} while (1);
return 0;
}
int WinMMDrv_MIDI_StartPlayback(void (*service)(void))
{
MMRESULT rv;
WinMMDrv_MIDI_HaltPlayback();
midiThreadService = service;
midiThreadQuitEvent = CreateEvent(nullptr, FALSE, FALSE, nullptr);
if (!midiThreadQuitEvent) {
ErrorCode = WinMMErr_MIDICreateEvent;
return WinMMErr_Error;
}
if (!midiStreamRunning) {
rv = midiStreamRestart(midiStream);
if (rv != MMSYSERR_NOERROR) {
midi_error(rv, "MIDI_StartPlayback midiStreamRestart");
WinMMDrv_MIDI_HaltPlayback();
ErrorCode = WinMMErr_MIDIStreamRestart;
return WinMMErr_Error;
}
midiStreamRunning = TRUE;
}
midiThread = CreateThread(nullptr, 0, midiDataThread, 0, 0, 0);
if (!midiThread) {
WinMMDrv_MIDI_HaltPlayback();
ErrorCode = WinMMErr_MIDIPlayThread;
return WinMMErr_Error;
}
midiLastDivision = 0;
return WinMMErr_Ok;
}
void WinMMDrv_MIDI_HaltPlayback(void)
{
MMRESULT rv;
if (midiThread) {
SetEvent(midiThreadQuitEvent);
WaitForSingleObject(midiThread, INFINITE);
// MV_Printf("WinMM MIDI_HaltPlayback synched\n");
CloseHandle(midiThread);
}
if (midiThreadQuitEvent) {
CloseHandle(midiThreadQuitEvent);
}
if (midiStreamRunning) {
// MV_Printf("stopping stream\n");
rv = midiStreamStop(midiStream);
if (rv != MMSYSERR_NOERROR) {
midi_error(rv, "WinMM MIDI_HaltPlayback midiStreamStop");
}
// MV_Printf("stream stopped\n");
midiStreamRunning = FALSE;
}
midi_free_buffers();
midiThread = 0;
midiThreadQuitEvent = 0;
}
void WinMMDrv_MIDI_SetTempo(int tempo, int division)
{
MMRESULT rv;
MIDIPROPTEMPO propTempo;
MIDIPROPTIMEDIV propTimediv;
BOOL running = midiStreamRunning;
//MV_Printf("MIDI_SetTempo %d/%d\n", tempo, division);
propTempo.cbStruct = sizeof(MIDIPROPTEMPO);
propTempo.dwTempo = 60000000l / tempo;
propTimediv.cbStruct = sizeof(MIDIPROPTIMEDIV);
propTimediv.dwTimeDiv = division;
if (midiLastDivision != division) {
// changing the division means halting the stream
WinMMDrv_MIDI_HaltPlayback();
rv = midiStreamProperty(midiStream, (LPBYTE) &propTimediv, MIDIPROP_SET | MIDIPROP_TIMEDIV);
if (rv != MMSYSERR_NOERROR) {
midi_error(rv, "WinMM MIDI_SetTempo midiStreamProperty timediv");
}
}
rv = midiStreamProperty(midiStream, (LPBYTE) &propTempo, MIDIPROP_SET | MIDIPROP_TEMPO);
if (rv != MMSYSERR_NOERROR) {
midi_error(rv, "WinMM MIDI_SetTempo midiStreamProperty tempo");
}
if (midiLastDivision != division) {
if (running && WinMMDrv_MIDI_StartPlayback(midiThreadService) != WinMMErr_Ok) {
return;
}
midiLastDivision = division;
}
midiThreadQueueTicks = (int) ceil( ( ( (double) tempo * (double) division ) / 60.0 ) /
(double) THREAD_QUEUE_INTERVAL );
if (midiThreadQueueTicks <= 0) {
midiThreadQueueTicks = 1;
}
}
void WinMMDrv_MIDI_Lock(void)
{
DWORD err;
err = WaitForSingleObject(midiMutex, INFINITE);
if (err != WAIT_OBJECT_0) {
MV_Printf("WinMM midiMutex lock: wfso %d\n", (int) err);
}
}
void WinMMDrv_MIDI_Unlock(void)
{
ReleaseMutex(midiMutex);
}
// vim:ts=4:sw=4:expandtab:

View file

@ -1,33 +0,0 @@
/*
Copyright (C) 2009 Jonathon Fowler <jf@jonof.id.au>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "midifuncs.h"
int WinMMDrv_GetError(void);
const char *WinMMDrv_ErrorString( int ErrorNumber );
int WinMMDrv_MIDI_Init(midifuncs *);
void WinMMDrv_MIDI_Shutdown(void);
int WinMMDrv_MIDI_StartPlayback(void (*service)(void));
void WinMMDrv_MIDI_HaltPlayback(void);
void WinMMDrv_MIDI_SetTempo(int tempo, int division);
void WinMMDrv_MIDI_Lock(void);
void WinMMDrv_MIDI_Unlock(void);

View file

@ -1,210 +0,0 @@
/*
Copyright (C) 2009 Jonathon Fowler <jf@jonof.id.au>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/**
* Abstraction layer for hiding the various supported sound devices
* behind a common and opaque interface called on by MultiVoc.
*/
#include "drivers.h"
#include "driver_adlib.h"
#ifdef RENDERTYPESDL
# include "driver_sdl.h"
#endif
#ifdef _WIN32
# include "driver_directsound.h"
# include "driver_winmm.h"
#endif
int ASS_PCMSoundDriver = ASS_AutoDetect;
int ASS_MIDISoundDriver = ASS_AutoDetect;
int ASS_EMIDICard = -1;
#define UNSUPPORTED_PCM nullptr,nullptr,nullptr,nullptr,nullptr,nullptr
#define UNSUPPORTED_MIDI nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr
#define UNSUPPORTED_COMPLETELY nullptr, nullptr, UNSUPPORTED_PCM, UNSUPPORTED_MIDI
static struct {
const char * DriverName;
int (*GetError)(void);
const char *(*ErrorString)(int);
int (*PCM_Init)(int *, int *, void *);
void (*PCM_Shutdown)(void);
int (*PCM_BeginPlayback)(char *, int, int, void (*)(void));
void (*PCM_StopPlayback)(void);
void (*PCM_Lock)(void);
void (*PCM_Unlock)(void);
int (*MIDI_Init)(midifuncs *);
void (*MIDI_Shutdown)(void);
int (*MIDI_StartPlayback)(void (*service)(void));
void (*MIDI_HaltPlayback)(void);
void (*MIDI_SetTempo)(int tempo, int division);
void (*MIDI_Lock)(void);
void (*MIDI_Unlock)(void);
} SoundDrivers[ASS_NumSoundCards] = {
// Simple DirectMedia Layer
{
"SDL",
#ifdef RENDERTYPESDL
SDLDrv_GetError,
SDLDrv_ErrorString,
SDLDrv_PCM_Init,
SDLDrv_PCM_Shutdown,
SDLDrv_PCM_BeginPlayback,
SDLDrv_PCM_StopPlayback,
SDLDrv_PCM_Lock,
SDLDrv_PCM_Unlock,
UNSUPPORTED_MIDI,
#else
UNSUPPORTED_COMPLETELY
#endif
},
// Windows DirectSound
{
"DirectSound",
#ifdef RENDERTYPEWIN
DirectSoundDrv_GetError,
DirectSoundDrv_ErrorString,
DirectSoundDrv_PCM_Init,
DirectSoundDrv_PCM_Shutdown,
DirectSoundDrv_PCM_BeginPlayback,
DirectSoundDrv_PCM_StopPlayback,
DirectSoundDrv_PCM_Lock,
DirectSoundDrv_PCM_Unlock,
UNSUPPORTED_MIDI,
#else
UNSUPPORTED_COMPLETELY
#endif
},
// OPL3 emulation
{
"Nuked OPL3 AdLib emulator",
AdLibDrv_GetError,
AdLibDrv_ErrorString,
UNSUPPORTED_PCM,
AdLibDrv_MIDI_Init,
AdLibDrv_MIDI_Shutdown,
AdLibDrv_MIDI_StartPlayback,
AdLibDrv_MIDI_HaltPlayback,
AdLibDrv_MIDI_SetTempo,
nullptr,
nullptr,
},
// Windows MultiMedia system
{
"WinMM",
#ifdef _WIN32
WinMMDrv_GetError,
WinMMDrv_ErrorString,
UNSUPPORTED_PCM,
WinMMDrv_MIDI_Init,
WinMMDrv_MIDI_Shutdown,
WinMMDrv_MIDI_StartPlayback,
WinMMDrv_MIDI_HaltPlayback,
WinMMDrv_MIDI_SetTempo,
WinMMDrv_MIDI_Lock,
WinMMDrv_MIDI_Unlock,
#else
UNSUPPORTED_COMPLETELY
#endif
},
};
int SoundDriver_IsPCMSupported(int driver) { return (SoundDrivers[driver].PCM_Init != 0); }
int SoundDriver_IsMIDISupported(int driver) { return (SoundDrivers[driver].MIDI_Init != 0); }
const char *SoundDriver_GetName(int driver) { return SoundDrivers[driver].DriverName; }
int SoundDriver_PCM_GetError(void)
{
if (!SoundDriver_IsPCMSupported(ASS_PCMSoundDriver))
return -1;
return SoundDrivers[ASS_PCMSoundDriver].GetError();
}
const char * SoundDriver_PCM_ErrorString( int ErrorNumber )
{
if (ASS_PCMSoundDriver < 0 || ASS_PCMSoundDriver >= ASS_NumSoundCards)
return "No sound driver selected.";
if (!SoundDriver_IsPCMSupported(ASS_PCMSoundDriver))
return "Unsupported sound driver selected.";
return SoundDrivers[ASS_PCMSoundDriver].ErrorString(ErrorNumber);
}
int SoundDriver_MIDI_GetError(void)
{
if (!SoundDriver_IsMIDISupported(ASS_MIDISoundDriver))
return -1;
return SoundDrivers[ASS_MIDISoundDriver].GetError();
}
const char * SoundDriver_MIDI_ErrorString( int ErrorNumber )
{
if (ASS_MIDISoundDriver < 0 || ASS_MIDISoundDriver >= ASS_NumSoundCards)
return "No sound driver selected.";
if (!SoundDriver_IsMIDISupported(ASS_MIDISoundDriver))
return "Unsupported sound driver selected.";
return SoundDrivers[ASS_MIDISoundDriver].ErrorString(ErrorNumber);
}
int SoundDriver_PCM_Init(int *mixrate, int *numchannels, void *initdata)
{
return SoundDrivers[ASS_PCMSoundDriver].PCM_Init(mixrate, numchannels, initdata);
}
int SoundDriver_PCM_BeginPlayback(char *BufferStart, int BufferSize, int NumDivisions, void (*CallBackFunc)(void))
{
return SoundDrivers[ASS_PCMSoundDriver].PCM_BeginPlayback(BufferStart, BufferSize, NumDivisions, CallBackFunc);
}
void SoundDriver_PCM_Shutdown(void) { SoundDrivers[ASS_PCMSoundDriver].PCM_Shutdown(); }
void SoundDriver_PCM_StopPlayback(void) { SoundDrivers[ASS_PCMSoundDriver].PCM_StopPlayback(); }
void SoundDriver_PCM_Lock(void) { SoundDrivers[ASS_PCMSoundDriver].PCM_Lock(); }
void SoundDriver_PCM_Unlock(void) { SoundDrivers[ASS_PCMSoundDriver].PCM_Unlock(); }
int SoundDriver_MIDI_Init(midifuncs *funcs) { return SoundDrivers[ASS_MIDISoundDriver].MIDI_Init(funcs); }
int SoundDriver_MIDI_StartPlayback(void (*service)(void)) { return SoundDrivers[ASS_MIDISoundDriver].MIDI_StartPlayback(service); }
void SoundDriver_MIDI_Shutdown(void) { SoundDrivers[ASS_MIDISoundDriver].MIDI_Shutdown(); }
void SoundDriver_MIDI_HaltPlayback(void) { SoundDrivers[ASS_MIDISoundDriver].MIDI_HaltPlayback(); }
void SoundDriver_MIDI_SetTempo(int tempo, int division) { SoundDrivers[ASS_MIDISoundDriver].MIDI_SetTempo(tempo, division); }
void SoundDriver_MIDI_Lock(void) { if (SoundDrivers[ASS_MIDISoundDriver].MIDI_Lock) SoundDrivers[ASS_MIDISoundDriver].MIDI_Lock(); }
void SoundDriver_MIDI_Unlock(void) { if (SoundDrivers[ASS_MIDISoundDriver].MIDI_Unlock) SoundDrivers[ASS_MIDISoundDriver].MIDI_Unlock(); }
// vim:ts=4:sw=4:expandtab:

View file

@ -1,537 +0,0 @@
/*
Copyright (C) 2009 Jonathon Fowler <jf@jonof.id.au>
Copyright (C) 2015 EDuke32 developers
Copyright (C) 2015 Voidpoint, LLC
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* Raw, WAV, and VOC source support for MultiVoc
*/
#include "_multivc.h"
#include "compat.h"
#include "multivoc.h"
#include "pitch.h"
#include "pragmas.h"
static playbackstatus MV_GetNextWAVBlock(VoiceNode *voice)
{
if (voice->BlockLength == 0)
{
if (voice->LoopStart == nullptr)
return NoMoreData;
voice->BlockLength = voice->LoopSize;
voice->NextBlock = voice->LoopStart;
voice->length = 0;
voice->position = 0;
}
voice->sound = voice->NextBlock;
voice->position -= voice->length;
voice->length = min(voice->BlockLength, 0x8000u);
voice->NextBlock += voice->length * ((voice->channels * voice->bits) >> 3);
voice->BlockLength -= voice->length;
voice->length <<= 16;
return KeepPlaying;
}
static playbackstatus MV_GetNextVOCBlock(VoiceNode *voice)
{
size_t blocklength = 0;
uint32_t samplespeed = 0; // XXX: compiler-happy on synthesis
uint32_t tc = 0;
unsigned BitsPerSample;
unsigned Channels;
unsigned Format;
if (voice->BlockLength > 0)
{
voice->position -= voice->length;
voice->sound += (voice->length >> 16) * ((voice->channels * voice->bits) >> 3);
voice->length = min(voice->BlockLength, 0x8000u);
voice->BlockLength -= voice->length;
voice->length <<= 16;
return KeepPlaying;
}
auto ptr = (uint8_t const *)voice->NextBlock;
voice->Paused = FALSE;
int voicemode = 0;
int blocktype = 0;
int lastblocktype = 0;
int packtype = 0;
int done = FALSE;
do
{
// Stop playing if we get a null pointer
if (ptr == nullptr)
{
done = 2;
break;
}
// terminator is not mandatory according to
// http://wiki.multimedia.cx/index.php?title=Creative_Voice
if (ptr - (uint8_t *)voice->rawdataptr >= voice->ptrlength)
blocktype = 0; // fake a terminator
else
blocktype = *ptr;
if (blocktype != 0)
blocklength = ptr[1]|(ptr[2]<<8)|(ptr[3]<<16);
else
blocklength = 0;
// would need one byte pad at end of alloc'd region:
// blocklength = B_LITTLE32(*(uint32_t *)(ptr + 1)) & 0x00ffffff;
ptr += 4;
switch (blocktype)
{
case 0 :
end_of_data:
// End of data
if ((voice->LoopStart == nullptr) ||
((intptr_t) voice->LoopStart >= ((intptr_t) ptr - 4)))
{
done = 2;
}
else
{
voice->NextBlock = voice->LoopStart;
voice->BlockLength = 0;
voice->position = 0;
return MV_GetNextVOCBlock(voice);
}
break;
case 1 :
// Sound data block
voice->bits = 8;
voice->channels = voicemode + 1;
if (lastblocktype != 8)
{
tc = (uint32_t)*ptr << 8;
packtype = *(ptr + 1);
}
ptr += 2;
blocklength -= 2;
samplespeed = 256000000L / (voice->channels * (65536 - tc));
// Skip packed or stereo data
if ((packtype != 0) || (voicemode != 0 && voicemode != 1))
ptr += blocklength;
else
done = TRUE;
if (ptr - (uint8_t *)voice->rawdataptr >= voice->ptrlength)
goto end_of_data;
voicemode = 0;
break;
case 2 :
// Sound continuation block
samplespeed = voice->SamplingRate;
done = TRUE;
break;
case 3 :
// Silence
case 4 :
// Marker
case 5 :
// ASCII string
// All not implemented.
ptr += blocklength;
break;
case 6 :
// Repeat begin
if (voice->LoopEnd == nullptr)
{
voice->LoopCount = B_LITTLE16(*(uint16_t const *)ptr);
voice->LoopStart = (char *)((intptr_t) ptr + blocklength);
}
ptr += blocklength;
break;
case 7 :
// Repeat end
ptr += blocklength;
if (lastblocktype == 6)
voice->LoopCount = 0;
else
{
if ((voice->LoopCount > 0) && (voice->LoopStart != nullptr))
{
ptr = (uint8_t const *) voice->LoopStart;
if (voice->LoopCount < 0xffff)
{
if (--voice->LoopCount == 0)
voice->LoopStart = nullptr;
}
}
}
break;
case 8 :
// Extended block
voice->bits = 8;
voice->channels = 1;
tc = B_LITTLE16(*(uint16_t const *)ptr);
packtype = *(ptr + 2);
voicemode = *(ptr + 3);
ptr += blocklength;
break;
case 9 :
// New sound data block
samplespeed = B_LITTLE32(*(uint32_t const *)ptr);
BitsPerSample = (unsigned)*(ptr + 4);
Channels = (unsigned)*(ptr + 5);
Format = (unsigned)B_LITTLE16(*(uint16_t const *)(ptr + 6));
if ((BitsPerSample == 8) && (Channels == 1 || Channels == 2) && (Format == VOC_8BIT))
{
ptr += 12;
blocklength -= 12;
voice->bits = 8;
voice->channels = Channels;
done = TRUE;
}
else if ((BitsPerSample == 16) && (Channels == 1 || Channels == 2) && (Format == VOC_16BIT))
{
ptr += 12;
blocklength -= 12;
voice->bits = 16;
voice->channels = Channels;
done = TRUE;
}
else
{
ptr += blocklength;
}
// CAUTION:
// SNAKRM.VOC is corrupt! blocklength gets us beyond the
// end of the file.
if (ptr - (uint8_t *)voice->rawdataptr >= voice->ptrlength)
goto end_of_data;
break;
default :
// Unknown data. Probably not a VOC file.
done = 2;
break;
}
lastblocktype = blocktype;
}
while (!done);
if (done != 2)
{
voice->NextBlock = (char const *)ptr + blocklength;
voice->sound = (char const *)ptr;
// CODEDUP multivoc.c MV_SetVoicePitch
voice->SamplingRate = samplespeed;
voice->RateScale = divideu32(voice->SamplingRate * voice->PitchScale, MV_MixRate);
// Multiply by MV_MIXBUFFERSIZE - 1
voice->FixedPointBufferSize = (voice->RateScale * MV_MIXBUFFERSIZE) -
voice->RateScale;
if (voice->LoopEnd != nullptr)
{
if (blocklength > (uintptr_t)voice->LoopEnd)
blocklength = (uintptr_t)voice->LoopEnd;
else
voice->LoopEnd = (char *)blocklength;
voice->LoopStart = voice->sound + (uintptr_t)voice->LoopStart;
voice->LoopEnd = voice->sound + (uintptr_t)voice->LoopEnd;
voice->LoopSize = voice->LoopEnd - voice->LoopStart;
}
if (voice->bits == 16)
blocklength /= 2;
if (voice->channels == 2)
blocklength /= 2;
voice->position = 0;
voice->length = min<uint32_t>(blocklength, 0x8000u);
voice->BlockLength = blocklength - voice->length;
voice->length <<= 16;
MV_SetVoiceMixMode(voice);
return KeepPlaying;
}
return NoMoreData;
}
static playbackstatus MV_GetNextRAWBlock(VoiceNode *voice)
{
if (voice->BlockLength == 0)
{
if (voice->LoopStart == NULL)
return NoMoreData;
voice->BlockLength = voice->LoopSize;
voice->NextBlock = voice->LoopStart;
voice->length = 0;
voice->position = 0;
}
voice->sound = voice->NextBlock;
voice->position -= voice->length;
voice->length = min(voice->BlockLength, 0x8000u);
voice->NextBlock += voice->length * (voice->channels * voice->bits / 8);
voice->BlockLength -= voice->length;
voice->length <<= 16;
return KeepPlaying;
}
int MV_PlayWAV3D(char *ptr, uint32_t length, int loophow, int pitchoffset, int angle, int distance,
int priority, float volume, intptr_t callbackval)
{
if (!MV_Installed)
return MV_Error;
if (distance < 0)
{
distance = -distance;
angle += MV_NUMPANPOSITIONS / 2;
}
int const vol = MIX_VOLUME(distance);
// Ensure angle is within 0 - 127
angle &= MV_MAXPANPOSITION;
return MV_PlayWAV(ptr, length, loophow, -1, pitchoffset, max(0, 255 - distance),
MV_PanTable[ angle ][ vol ].left, MV_PanTable[ angle ][ vol ].right, priority, volume, callbackval);
}
int MV_PlayWAV(char *ptr, uint32_t length, int loopstart, int loopend, int pitchoffset, int vol,
int left, int right, int priority, float volume, intptr_t callbackval)
{
if (!MV_Installed)
return MV_Error;
riff_header riff;
memcpy(&riff, ptr, sizeof(riff_header));
riff.file_size = B_LITTLE32(riff.file_size);
riff.format_size = B_LITTLE32(riff.format_size);
if ((memcmp(riff.RIFF, "RIFF", 4) != 0) || (memcmp(riff.WAVE, "WAVE", 4) != 0) || (memcmp(riff.fmt, "fmt ", 4) != 0))
return MV_SetErrorCode(MV_InvalidFile);
format_header format;
memcpy(&format, ptr + sizeof(riff_header), sizeof(format_header));
format.wFormatTag = B_LITTLE16(format.wFormatTag);
format.nChannels = B_LITTLE16(format.nChannels);
format.nSamplesPerSec = B_LITTLE32(format.nSamplesPerSec);
format.nAvgBytesPerSec = B_LITTLE32(format.nAvgBytesPerSec);
format.nBlockAlign = B_LITTLE16(format.nBlockAlign);
format.nBitsPerSample = B_LITTLE16(format.nBitsPerSample);
data_header data;
memcpy(&data, ptr + sizeof(riff_header) + riff.format_size, sizeof(data_header));
data.size = B_LITTLE32(data.size);
// Check if it's PCM data.
if (format.wFormatTag != 1 || (format.nChannels != 1 && format.nChannels != 2) ||
((format.nBitsPerSample != 8) && (format.nBitsPerSample != 16)) || memcmp(data.DATA, "data", 4) != 0)
return MV_SetErrorCode(MV_InvalidFile);
// Request a voice from the voice pool
VoiceNode *voice = MV_AllocVoice(priority);
if (voice == nullptr)
return MV_SetErrorCode(MV_NoVoices);
voice->wavetype = FMT_WAV;
voice->bits = format.nBitsPerSample;
voice->channels = format.nChannels;
voice->GetSound = MV_GetNextWAVBlock;
int blocklen = data.size;
if (voice->bits == 16)
{
data.size &= ~1;
blocklen /= 2;
}
if (voice->channels == 2)
{
data.size &= ~1;
blocklen /= 2;
}
voice->rawdataptr = (uint8_t *)ptr;
voice->ptrlength = length;
voice->Paused = FALSE;
voice->LoopCount = 0;
voice->position = 0;
voice->length = 0;
voice->BlockLength = blocklen;
voice->NextBlock = (char *)((intptr_t) ptr + sizeof(riff_header) + riff.format_size + sizeof(data_header));
voice->next = nullptr;
voice->prev = nullptr;
voice->priority = priority;
voice->callbackval = callbackval;
voice->LoopStart = loopstart >= 0 ? voice->NextBlock : nullptr;
voice->LoopEnd = nullptr;
voice->LoopSize = loopend > 0 ? loopend - loopstart + 1 : blocklen;
MV_SetVoicePitch(voice, format.nSamplesPerSec, pitchoffset);
MV_SetVoiceVolume(voice, vol, left, right, volume);
MV_PlayVoice(voice);
return voice->handle;
}
int MV_PlayVOC3D(char *ptr, uint32_t length, int loophow, int pitchoffset, int angle,
int distance, int priority, float volume, intptr_t callbackval)
{
if (!MV_Installed)
return MV_Error;
if (distance < 0)
{
distance = -distance;
angle += MV_NUMPANPOSITIONS / 2;
}
int const vol = MIX_VOLUME(distance);
// Ensure angle is within 0 - 127
angle &= MV_MAXPANPOSITION;
return MV_PlayVOC(ptr, length, loophow, -1, pitchoffset, max(0, 255 - distance),
MV_PanTable[ angle ][ vol ].left, MV_PanTable[ angle ][ vol ].right, priority, volume, callbackval);
}
int MV_PlayVOC(char *ptr, uint32_t length, int loopstart, int loopend, int pitchoffset, int vol,
int left, int right, int priority, float volume, intptr_t callbackval)
{
if (!MV_Installed)
return MV_Error;
// Make sure it looks like a valid VOC file.
if (memcmp(ptr, "Creative Voice File", 19) != 0)
return MV_SetErrorCode(MV_InvalidFile);
// Request a voice from the voice pool
VoiceNode *voice = MV_AllocVoice(priority);
if (voice == nullptr)
return MV_SetErrorCode(MV_NoVoices);
voice->rawdataptr = (uint8_t *)ptr;
voice->ptrlength = length;
voice->Paused = FALSE;
voice->wavetype = FMT_VOC;
voice->bits = 8;
voice->channels = 1;
voice->GetSound = MV_GetNextVOCBlock;
voice->NextBlock = ptr + B_LITTLE16(*(uint16_t *)(ptr + 0x14));
voice->LoopCount = 0;
voice->BlockLength = 0;
voice->PitchScale = PITCH_GetScale(pitchoffset);
voice->length = 0;
voice->next = nullptr;
voice->prev = nullptr;
voice->priority = priority;
voice->callbackval = callbackval;
voice->LoopStart = loopstart >= 0 ? voice->NextBlock : nullptr;
voice->LoopEnd = nullptr;
voice->LoopSize = loopend - loopstart + 1;
voice->volume = volume;
MV_SetVoiceVolume(voice, vol, left, right, volume);
MV_PlayVoice(voice);
return voice->handle;
}
int MV_PlayRAW(char *ptr, uint32_t length, int rate, char *loopstart, char *loopend, int pitchoffset, int vol,
int left, int right, int priority, float volume, intptr_t callbackval)
{
if (!MV_Installed)
return MV_Error;
// Request a voice from the voice pool
VoiceNode *voice = MV_AllocVoice(priority);
if (voice == NULL)
{
MV_SetErrorCode(MV_NoVoices);
return MV_Error;
}
voice->rawdataptr = (uint8_t *)ptr;
voice->ptrlength = length;
voice->Paused = FALSE;
voice->wavetype = FMT_RAW;
voice->bits = 8;
voice->channels = 1;
voice->GetSound = MV_GetNextRAWBlock;
voice->NextBlock = ptr;
voice->LoopCount = 0;
voice->position = 0;
voice->BlockLength = length;
voice->PitchScale = PITCH_GetScale(pitchoffset);
voice->length = 0;
voice->next = NULL;
voice->prev = NULL;
voice->priority = priority;
voice->callbackval = callbackval;
voice->LoopStart = loopstart;
voice->LoopEnd = loopend;
voice->LoopSize = loopend - loopstart + 1;
voice->volume = volume;
MV_SetVoicePitch(voice, rate, pitchoffset);
MV_SetVoiceVolume(voice, vol, left, right, volume);
MV_PlayVoice(voice);
return voice->handle;
}

View file

@ -1,225 +0,0 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2016 EDuke32 developers and contributors
This file is part of EDuke32.
EDuke32 is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "fx_man.h"
#include "compat.h"
#include "drivers.h"
#include "driver_adlib.h"
#include "midi.h"
#include "multivoc.h"
#include "osd.h"
int FX_ErrorCode = FX_Ok;
int FX_Installed;
const char *FX_ErrorString(int const ErrorNumber)
{
const char *ErrorString;
switch (ErrorNumber)
{
case FX_Warning:
case FX_Error: ErrorString = FX_ErrorString(FX_ErrorCode); break;
case FX_Ok: ErrorString = "Fx ok."; break;
case FX_MultiVocError: ErrorString = MV_ErrorString(MV_Error); break;
default: ErrorString = "Unknown Fx error code."; break;
}
return ErrorString;
}
int FX_Init(int numvoices, int numchannels, int mixrate, void *initdata)
{
if (FX_Installed)
FX_Shutdown();
int SoundCard = ASS_AutoDetect;
if (SoundCard == ASS_AutoDetect)
{
#if defined RENDERTYPESDL
SoundCard = ASS_SDL;
#elif defined RENDERTYPEWIN
SoundCard = ASS_DirectSound;
#endif
}
if (SoundCard < 0 || SoundCard >= ASS_NumSoundCards)
{
FX_SetErrorCode(FX_InvalidCard);
return FX_Error;
}
if (SoundDriver_IsPCMSupported(SoundCard) == 0)
{
// unsupported cards fall back to no sound
FX_SetErrorCode(FX_InvalidCard);
return FX_Error;
}
int status = FX_Ok;
if (MV_Init(SoundCard, mixrate, numvoices, numchannels, initdata) != MV_Ok)
{
FX_SetErrorCode(FX_MultiVocError);
status = FX_Error;
}
if (status == FX_Ok)
FX_Installed = TRUE;
return status;
}
int FX_Shutdown(void)
{
if (!FX_Installed)
return FX_Ok;
int status = MV_Shutdown();
if (status != MV_Ok)
{
FX_SetErrorCode(FX_MultiVocError);
status = FX_Error;
}
FX_Installed = FALSE;
return status;
}
int FX_GetDevice()
{
return ASS_PCMSoundDriver;
}
static wavefmt_t FX_DetectFormat(char const * const ptr, uint32_t length)
{
if (length < 12)
return FMT_UNKNOWN;
wavefmt_t fmt = FMT_UNKNOWN;
switch (B_LITTLE32(*(int const *)ptr))
{
case 'C' + ('r' << 8) + ('e' << 16) + ('a' << 24): // Crea
fmt = FMT_VOC;
break;
case 'O' + ('g' << 8) + ('g' << 16) + ('S' << 24): // OggS
fmt = FMT_VORBIS;
break;
case 'R' + ('I' << 8) + ('F' << 16) + ('F' << 24): // RIFF
switch (B_LITTLE32(*(int const *)(ptr + 8)))
{
case 'W' + ('A' << 8) + ('V' << 16) + ('E' << 24): // WAVE
fmt = FMT_WAV;
break;
}
break;
default:
break;
}
return fmt;
}
int FX_Play(char *ptr, uint32_t ptrlength, int loopstart, int loopend, int pitchoffset,
int vol, int left, int right, int priority, float volume, intptr_t callbackval)
{
static constexpr decltype(MV_PlayVOC) *func[] =
{ nullptr, nullptr, MV_PlayVOC, MV_PlayWAV, nullptr, nullptr, MV_PlayVorbis, nullptr, nullptr, nullptr };
//EDUKE32_STATIC_ASSERT(FMT_MAX == ARRAY_SIZE(func));
wavefmt_t const fmt = FX_DetectFormat(ptr, ptrlength);
int handle =
(func[fmt]) ? func[fmt](ptr, ptrlength, loopstart, loopend, pitchoffset, vol, left, right, priority, volume, callbackval) : -1;
if (handle <= MV_Ok)
{
FX_SetErrorCode(FX_MultiVocError);
handle = FX_Warning;
}
return handle;
}
int FX_Play3D(char *ptr, uint32_t ptrlength, int loophow, int pitchoffset, int angle, int distance,
int priority, float volume, intptr_t callbackval)
{
static constexpr decltype(MV_PlayVOC3D) *func[] =
{ nullptr, nullptr, MV_PlayVOC3D, MV_PlayWAV3D, nullptr, nullptr, MV_PlayVorbis3D, nullptr, nullptr, nullptr };
//EDUKE32_STATIC_ASSERT(FMT_MAX == ARRAY_SIZE(func));
wavefmt_t const fmt = FX_DetectFormat(ptr, ptrlength);
int handle =
(func[fmt]) ? func[fmt](ptr, ptrlength, loophow, pitchoffset, angle, distance, priority, volume, callbackval) : -1;
if (handle <= MV_Ok)
{
FX_SetErrorCode(FX_MultiVocError);
handle = FX_Warning;
}
return handle;
}
int FX_PlayRaw(char *ptr, uint32_t ptrlength, int rate, int pitchoffset, int vol,
int left, int right, int priority, float volume, intptr_t callbackval)
{
int handle = MV_PlayRAW(ptr, ptrlength, rate, NULL, NULL, pitchoffset, vol, left, right, priority, volume, callbackval);
if (handle <= MV_Ok)
{
FX_SetErrorCode(FX_MultiVocError);
handle = FX_Warning;
}
return handle;
}
int FX_PlayLoopedRaw(char *ptr, uint32_t ptrlength, char *loopstart, char *loopend, int rate,
int pitchoffset, int vol, int left, int right, int priority, float volume, intptr_t callbackval)
{
int handle = MV_PlayRAW(ptr, ptrlength, rate, loopstart, loopend, pitchoffset, vol, left, right, priority, volume, callbackval);
if (handle <= MV_Ok)
{
FX_SetErrorCode(FX_MultiVocError);
handle = FX_Warning;
}
return handle;
}
int FX_SetPrintf(void (*function)(const char *, ...))
{
MV_SetPrintf(function);
return FX_Ok;
}

View file

@ -1,282 +0,0 @@
/*
Copyright (C) 1994-1995 Apogee Software, Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <inttypes.h>
#include "al_midi.h"
AdLibTimbre ADLIB_TimbreBank[256] =
{
{ { 33, 33 }, { 143, 6 }, { 242, 242 }, { 69, 118 }, { 0, 0 }, 8, 0, 0 },
{ { 49, 33 }, { 75, 0 }, { 242, 242 }, { 84, 86 }, { 0, 0 }, 8, 0, 0 },
{ { 49, 33 }, { 73, 0 }, { 242, 242 }, { 85, 118 }, { 0, 0 }, 8, 0, 0 },
{ { 177, 97 }, { 14, 0 }, { 242, 243 }, { 59, 11 }, { 0, 0 }, 6, 0, 0 },
{ { 1, 33 }, { 87, 0 }, { 241, 241 }, { 56, 40 }, { 0, 0 }, 0, 0, 0 },
{ { 1, 33 }, { 147, 0 }, { 241, 241 }, { 56, 40 }, { 0, 0 }, 0, 0, 0 },
{ { 33, 54 }, { 128, 14 }, { 162, 241 }, { 1, 213 }, { 0, 0 }, 8, 0, 0 },
{ { 1, 1 }, { 146, 0 }, { 194, 194 }, { 168, 88 }, { 0, 0 }, 10, 0, 0 },
{ { 12, 129 }, { 92, 0 }, { 246, 243 }, { 84, 181 }, { 0, 0 }, 0, 0, 0 },
{ { 7, 17 }, { 151, 128 }, { 246, 245 }, { 50, 17 }, { 0, 0 }, 2, 0, 0 },
{ { 23, 1 }, { 33, 0 }, { 86, 246 }, { 4, 4 }, { 0, 0 }, 2, 0, 0 },
{ { 24, 129 }, { 98, 0 }, { 243, 242 }, { 230, 246 }, { 0, 0 }, 0, 0, 0 },
{ { 24, 33 }, { 35, 0 }, { 247, 229 }, { 85, 216 }, { 0, 0 }, 0, 0, 0 },
{ { 21, 1 }, { 145, 0 }, { 246, 246 }, { 166, 230 }, { 0, 0 }, 4, 0, 0 },
{ { 69, 129 }, { 89, 128 }, { 211, 163 }, { 130, 227 }, { 0, 0 }, 12, 0, 0 },
{ { 3, 129 }, { 73, 128 }, { 116, 179 }, { 85, 5 }, { 1, 0 }, 4, 0, 0 },
{ { 113, 49 }, { 146, 0 }, { 246, 241 }, { 20, 7 }, { 0, 0 }, 2, 0, 0 },
{ { 114, 48 }, { 20, 0 }, { 199, 199 }, { 88, 8 }, { 0, 0 }, 2, 0, 0 },
{ { 112, 177 }, { 68, 0 }, { 170, 138 }, { 24, 8 }, { 0, 0 }, 4, 0, 0 },
{ { 35, 177 }, { 147, 0 }, { 151, 85 }, { 35, 20 }, { 1, 0 }, 4, 0, 0 },
{ { 97, 177 }, { 19, 128 }, { 151, 85 }, { 4, 4 }, { 1, 0 }, 0, 0, 0 },
{ { 36, 177 }, { 72, 0 }, { 152, 70 }, { 42, 26 }, { 1, 0 }, 12, 0, 0 },
{ { 97, 33 }, { 19, 0 }, { 145, 97 }, { 6, 7 }, { 1, 0 }, 10, 0, 0 },
{ { 33, 161 }, { 19, 137 }, { 113, 97 }, { 6, 7 }, { 0, 0 }, 6, 0, 0 },
{ { 2, 65 }, { 156, 128 }, { 243, 243 }, { 148, 200 }, { 1, 0 }, 12, 0, 0 },
{ { 3, 17 }, { 84, 0 }, { 243, 241 }, { 154, 231 }, { 1, 0 }, 12, 0, 0 },
{ { 35, 33 }, { 95, 0 }, { 241, 242 }, { 58, 248 }, { 0, 0 }, 0, 0, 0 },
{ { 3, 33 }, { 135, 128 }, { 246, 243 }, { 34, 243 }, { 1, 0 }, 6, 0, 0 },
{ { 3, 33 }, { 71, 0 }, { 249, 246 }, { 84, 58 }, { 0, 0 }, 0, 0, 0 },
{ { 35, 33 }, { 72, 0 }, { 149, 132 }, { 25, 25 }, { 1, 0 }, 8, 0, 0 },
{ { 35, 33 }, { 74, 0 }, { 149, 148 }, { 25, 25 }, { 1, 0 }, 8, 0, 0 },
{ { 9, 132 }, { 161, 128 }, { 32, 209 }, { 79, 248 }, { 0, 0 }, 8, 0, 0 },
{ { 33, 162 }, { 30, 0 }, { 148, 195 }, { 6, 166 }, { 0, 0 }, 2, 0, 0 },
{ { 49, 49 }, { 18, 0 }, { 241, 241 }, { 40, 24 }, { 0, 0 }, 10, 0, 0 },
{ { 49, 49 }, { 141, 0 }, { 241, 241 }, { 232, 120 }, { 0, 0 }, 10, 0, 0 },
{ { 49, 50 }, { 91, 0 }, { 81, 113 }, { 40, 72 }, { 0, 0 }, 12, 0, 0 },
{ { 1, 33 }, { 139, 64 }, { 161, 242 }, { 154, 223 }, { 0, 0 }, 8, 0, 0 },
{ { 1, 33 }, { 137, 64 }, { 161, 242 }, { 154, 223 }, { 0, 0 }, 8, 0, 0 },
{ { 49, 49 }, { 139, 0 }, { 244, 241 }, { 232, 120 }, { 0, 0 }, 10, 0, 0 },
{ { 49, 49 }, { 18, 0 }, { 241, 241 }, { 40, 24 }, { 0, 0 }, 10, 0, 0 },
{ { 49, 33 }, { 21, 0 }, { 221, 86 }, { 19, 38 }, { 1, 0 }, 8, 0, 0 },
{ { 49, 33 }, { 22, 0 }, { 221, 102 }, { 19, 6 }, { 1, 0 }, 8, 0, 0 },
{ { 113, 49 }, { 73, 0 }, { 209, 97 }, { 28, 12 }, { 1, 0 }, 8, 0, 0 },
{ { 33, 35 }, { 77, 128 }, { 113, 114 }, { 18, 6 }, { 1, 0 }, 2, 0, 0 },
{ { 241, 225 }, { 64, 0 }, { 241, 111 }, { 33, 22 }, { 1, 0 }, 2, 0, 0 },
{ { 2, 1 }, { 26, 128 }, { 245, 133 }, { 117, 53 }, { 1, 0 }, 0, 0, 0 },
{ { 2, 1 }, { 29, 128 }, { 245, 243 }, { 117, 244 }, { 1, 0 }, 0, 0, 0 },
{ { 16, 17 }, { 65, 0 }, { 245, 242 }, { 5, 195 }, { 1, 0 }, 2, 0, 0 },
{ { 33, 162 }, { 155, 1 }, { 177, 114 }, { 37, 8 }, { 1, 0 }, 14, 0, 0 },
{ { 161, 33 }, { 152, 0 }, { 127, 63 }, { 3, 7 }, { 1, 1 }, 0, 0, 0 },
{ { 161, 97 }, { 147, 0 }, { 193, 79 }, { 18, 5 }, { 0, 0 }, 10, 0, 0 },
{ { 33, 97 }, { 24, 0 }, { 193, 79 }, { 34, 5 }, { 0, 0 }, 12, 0, 0 },
{ { 49, 114 }, { 91, 131 }, { 244, 138 }, { 21, 5 }, { 0, 0 }, 0, 0, 0 },
{ { 161, 97 }, { 144, 0 }, { 116, 113 }, { 57, 103 }, { 0, 0 }, 0, 0, 0 },
{ { 113, 114 }, { 87, 0 }, { 84, 122 }, { 5, 5 }, { 0, 0 }, 12, 0, 0 },
{ { 144, 65 }, { 0, 0 }, { 84, 165 }, { 99, 69 }, { 0, 0 }, 8, 0, 0 },
{ { 33, 33 }, { 146, 1 }, { 133, 143 }, { 23, 9 }, { 0, 0 }, 12, 0, 0 },
{ { 33, 33 }, { 148, 5 }, { 117, 143 }, { 23, 9 }, { 0, 0 }, 12, 0, 0 },
{ { 33, 97 }, { 148, 0 }, { 118, 130 }, { 21, 55 }, { 0, 0 }, 12, 0, 0 },
{ { 49, 33 }, { 67, 0 }, { 158, 98 }, { 23, 44 }, { 1, 1 }, 2, 0, 0 },
{ { 33, 33 }, { 155, 0 }, { 97, 127 }, { 106, 10 }, { 0, 0 }, 2, 0, 0 },
{ { 97, 34 }, { 138, 6 }, { 117, 116 }, { 31, 15 }, { 0, 0 }, 8, 0, 0 },
{ { 161, 33 }, { 134, 13 }, { 114, 113 }, { 85, 24 }, { 1, 0 }, 0, 0, 0 },
{ { 33, 33 }, { 77, 0 }, { 84, 166 }, { 60, 28 }, { 0, 0 }, 8, 0, 0 },
{ { 49, 97 }, { 143, 0 }, { 147, 114 }, { 2, 11 }, { 1, 0 }, 8, 0, 0 },
{ { 49, 97 }, { 142, 0 }, { 147, 114 }, { 3, 9 }, { 1, 0 }, 8, 0, 0 },
{ { 49, 97 }, { 145, 0 }, { 147, 130 }, { 3, 9 }, { 1, 0 }, 10, 0, 0 },
{ { 49, 97 }, { 142, 0 }, { 147, 114 }, { 15, 15 }, { 1, 0 }, 10, 0, 0 },
{ { 33, 33 }, { 75, 0 }, { 170, 143 }, { 22, 10 }, { 1, 0 }, 8, 0, 0 },
{ { 49, 33 }, { 144, 0 }, { 126, 139 }, { 23, 12 }, { 1, 1 }, 6, 0, 0 },
{ { 49, 50 }, { 129, 0 }, { 117, 97 }, { 25, 25 }, { 1, 0 }, 0, 0, 0 },
{ { 50, 33 }, { 144, 0 }, { 155, 114 }, { 33, 23 }, { 0, 0 }, 4, 0, 0 },
{ { 225, 225 }, { 31, 0 }, { 133, 101 }, { 95, 26 }, { 0, 0 }, 0, 0, 0 },
{ { 225, 225 }, { 70, 0 }, { 136, 101 }, { 95, 26 }, { 0, 0 }, 0, 0, 0 },
{ { 161, 33 }, { 156, 0 }, { 117, 117 }, { 31, 10 }, { 0, 0 }, 2, 0, 0 },
{ { 49, 33 }, { 139, 0 }, { 132, 101 }, { 88, 26 }, { 0, 0 }, 0, 0, 0 },
{ { 225, 161 }, { 76, 0 }, { 102, 101 }, { 86, 38 }, { 0, 0 }, 0, 0, 0 },
{ { 98, 161 }, { 203, 0 }, { 118, 85 }, { 70, 54 }, { 0, 0 }, 0, 0, 0 },
{ { 98, 161 }, { 153, 0 }, { 87, 86 }, { 7, 7 }, { 0, 0 }, 11, 0, 0 },
{ { 98, 161 }, { 147, 0 }, { 119, 118 }, { 7, 7 }, { 0, 0 }, 11, 0, 0 },
{ { 34, 33 }, { 89, 0 }, { 255, 255 }, { 3, 15 }, { 2, 0 }, 0, 0, 0 },
{ { 33, 33 }, { 14, 0 }, { 255, 255 }, { 15, 15 }, { 1, 1 }, 0, 0, 0 },
{ { 34, 33 }, { 70, 128 }, { 134, 100 }, { 85, 24 }, { 0, 0 }, 0, 0, 0 },
{ { 33, 161 }, { 69, 0 }, { 102, 150 }, { 18, 10 }, { 0, 0 }, 0, 0, 0 },
{ { 33, 34 }, { 139, 0 }, { 146, 145 }, { 42, 42 }, { 1, 0 }, 0, 0, 0 },
{ { 162, 97 }, { 158, 64 }, { 223, 111 }, { 5, 7 }, { 0, 0 }, 2, 0, 0 },
{ { 32, 96 }, { 26, 0 }, { 239, 143 }, { 1, 6 }, { 0, 2 }, 0, 0, 0 },
{ { 33, 33 }, { 143, 128 }, { 241, 244 }, { 41, 9 }, { 0, 0 }, 10, 0, 0 },
{ { 119, 161 }, { 165, 0 }, { 83, 160 }, { 148, 5 }, { 0, 0 }, 2, 0, 0 },
{ { 97, 177 }, { 31, 128 }, { 168, 37 }, { 17, 3 }, { 0, 0 }, 10, 0, 0 },
{ { 97, 97 }, { 23, 0 }, { 145, 85 }, { 52, 22 }, { 0, 0 }, 12, 0, 0 },
{ { 113, 114 }, { 93, 0 }, { 84, 106 }, { 1, 3 }, { 0, 0 }, 0, 0, 0 },
{ { 33, 162 }, { 151, 0 }, { 33, 66 }, { 67, 53 }, { 0, 0 }, 8, 0, 0 },
{ { 161, 33 }, { 28, 0 }, { 161, 49 }, { 119, 71 }, { 1, 1 }, 0, 0, 0 },
{ { 33, 97 }, { 137, 3 }, { 17, 66 }, { 51, 37 }, { 0, 0 }, 10, 0, 0 },
{ { 161, 33 }, { 21, 0 }, { 17, 207 }, { 71, 7 }, { 1, 0 }, 0, 0, 0 },
{ { 58, 81 }, { 206, 0 }, { 248, 134 }, { 246, 2 }, { 0, 0 }, 2, 0, 0 },
{ { 33, 33 }, { 21, 0 }, { 33, 65 }, { 35, 19 }, { 1, 0 }, 0, 0, 0 },
{ { 6, 1 }, { 91, 0 }, { 116, 165 }, { 149, 114 }, { 0, 0 }, 0, 0, 0 },
{ { 34, 97 }, { 146, 131 }, { 177, 242 }, { 129, 38 }, { 0, 0 }, 12, 0, 0 },
{ { 65, 66 }, { 77, 0 }, { 241, 242 }, { 81, 245 }, { 1, 0 }, 0, 0, 0 },
{ { 97, 163 }, { 148, 128 }, { 17, 17 }, { 81, 19 }, { 1, 0 }, 6, 0, 0 },
{ { 97, 161 }, { 140, 128 }, { 17, 29 }, { 49, 3 }, { 0, 0 }, 6, 0, 0 },
{ { 164, 97 }, { 76, 0 }, { 243, 129 }, { 115, 35 }, { 1, 0 }, 4, 0, 0 },
{ { 2, 7 }, { 133, 3 }, { 210, 242 }, { 83, 246 }, { 0, 1 }, 0, 0, 0 },
{ { 17, 19 }, { 12, 128 }, { 163, 162 }, { 17, 229 }, { 1, 0 }, 0, 0, 0 },
{ { 17, 17 }, { 6, 0 }, { 246, 242 }, { 65, 230 }, { 1, 2 }, 4, 0, 0 },
{ { 147, 145 }, { 145, 0 }, { 212, 235 }, { 50, 17 }, { 0, 1 }, 8, 0, 0 },
{ { 4, 1 }, { 79, 0 }, { 250, 194 }, { 86, 5 }, { 0, 0 }, 12, 0, 0 },
{ { 33, 34 }, { 73, 0 }, { 124, 111 }, { 32, 12 }, { 0, 1 }, 6, 0, 0 },
{ { 49, 33 }, { 133, 0 }, { 221, 86 }, { 51, 22 }, { 1, 0 }, 10, 0, 0 },
{ { 32, 33 }, { 4, 129 }, { 218, 143 }, { 5, 11 }, { 2, 0 }, 6, 0, 0 },
{ { 5, 3 }, { 106, 128 }, { 241, 195 }, { 229, 229 }, { 0, 0 }, 6, 0, 0 },
{ { 7, 2 }, { 21, 0 }, { 236, 248 }, { 38, 22 }, { 0, 0 }, 10, 0, 0 },
{ { 5, 1 }, { 157, 0 }, { 103, 223 }, { 53, 5 }, { 0, 0 }, 8, 0, 0 },
{ { 24, 18 }, { 150, 0 }, { 250, 248 }, { 40, 229 }, { 0, 0 }, 10, 0, 0 },
{ { 16, 0 }, { 134, 3 }, { 168, 250 }, { 7, 3 }, { 0, 0 }, 6, 0, 0 },
{ { 17, 16 }, { 65, 3 }, { 248, 243 }, { 71, 3 }, { 2, 0 }, 4, 0, 0 },
{ { 1, 16 }, { 142, 0 }, { 241, 243 }, { 6, 2 }, { 2, 0 }, 14, 0, 0 },
{ { 14, 192 }, { 0, 0 }, { 31, 31 }, { 0, 255 }, { 0, 3 }, 14, 0, 0 },
{ { 6, 3 }, { 128, 136 }, { 248, 86 }, { 36, 132 }, { 0, 2 }, 14, 0, 0 },
{ { 14, 208 }, { 0, 5 }, { 248, 52 }, { 0, 4 }, { 0, 3 }, 14, 0, 0 },
{ { 14, 192 }, { 0, 0 }, { 246, 31 }, { 0, 2 }, { 0, 3 }, 14, 0, 0 },
{ { 213, 218 }, { 149, 64 }, { 55, 86 }, { 163, 55 }, { 0, 0 }, 0, 0, 0 },
{ { 53, 20 }, { 92, 8 }, { 178, 244 }, { 97, 21 }, { 2, 0 }, 10, 0, 0 },
{ { 14, 208 }, { 0, 0 }, { 246, 79 }, { 0, 245 }, { 0, 3 }, 14, 0, 0 },
{ { 38, 228 }, { 0, 0 }, { 255, 18 }, { 1, 22 }, { 0, 1 }, 14, 0, 0 },
{ { 0, 0 }, { 0, 0 }, { 243, 246 }, { 240, 201 }, { 0, 2 }, 14, 0, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 0, 0 }, { 0, 0 }, { 252, 250 }, { 5, 23 }, { 2, 0 }, 14, 52, 0 },
{ { 0, 1 }, { 2, 0 }, { 255, 255 }, { 7, 8 }, { 0, 0 }, 0, 48, 0 },
{ { 0, 0 }, { 0, 0 }, { 252, 250 }, { 5, 23 }, { 2, 0 }, 14, 58, 0 },
{ { 0, 0 }, { 0, 0 }, { 246, 246 }, { 12, 6 }, { 0, 0 }, 4, 60, 0 },
{ { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 47, 0 },
{ { 0, 0 }, { 3, 0 }, { 248, 246 }, { 42, 69 }, { 0, 1 }, 4, 43, 0 },
{ { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 49, 0 },
{ { 0, 0 }, { 3, 0 }, { 248, 246 }, { 42, 69 }, { 0, 1 }, 4, 43, 0 },
{ { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 51, 0 },
{ { 0, 0 }, { 3, 0 }, { 248, 246 }, { 42, 69 }, { 0, 1 }, 4, 43, 0 },
{ { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 54, 0 },
{ { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 57, 0 },
{ { 0, 0 }, { 3, 0 }, { 248, 246 }, { 42, 69 }, { 0, 1 }, 4, 72, 0 },
{ { 12, 18 }, { 0, 0 }, { 246, 251 }, { 8, 71 }, { 0, 2 }, 10, 60, 0 },
{ { 14, 208 }, { 0, 10 }, { 245, 159 }, { 48, 2 }, { 0, 0 }, 14, 76, 0 },
{ { 14, 7 }, { 10, 93 }, { 228, 245 }, { 228, 229 }, { 3, 1 }, 6, 84, 0 },
{ { 2, 5 }, { 3, 10 }, { 180, 151 }, { 4, 247 }, { 0, 0 }, 14, 36, 0 },
{ { 78, 158 }, { 0, 0 }, { 246, 159 }, { 0, 2 }, { 0, 3 }, 14, 76, 0 },
{ { 17, 16 }, { 69, 8 }, { 248, 243 }, { 55, 5 }, { 2, 0 }, 8, 84, 0 },
{ { 14, 208 }, { 0, 0 }, { 246, 159 }, { 0, 2 }, { 0, 3 }, 14, 83, 0 },
{ { 128, 16 }, { 0, 13 }, { 255, 255 }, { 3, 20 }, { 3, 0 }, 12, 84, 0 },
{ { 14, 7 }, { 8, 81 }, { 248, 244 }, { 66, 228 }, { 0, 3 }, 14, 24, 0 },
{ { 14, 208 }, { 0, 10 }, { 245, 159 }, { 48, 2 }, { 0, 0 }, 14, 77, 0 },
{ { 1, 2 }, { 0, 0 }, { 250, 200 }, { 191, 151 }, { 0, 0 }, 7, 60, 0 },
{ { 1, 1 }, { 81, 0 }, { 250, 250 }, { 135, 183 }, { 0, 0 }, 6, 65, 0 },
{ { 1, 2 }, { 84, 0 }, { 250, 248 }, { 141, 184 }, { 0, 0 }, 6, 59, 0 },
{ { 1, 2 }, { 89, 0 }, { 250, 248 }, { 136, 182 }, { 0, 0 }, 6, 51, 0 },
{ { 1, 0 }, { 0, 0 }, { 249, 250 }, { 10, 6 }, { 3, 0 }, 14, 45, 0 },
{ { 0, 0 }, { 128, 0 }, { 249, 246 }, { 137, 108 }, { 3, 0 }, 14, 71, 0 },
{ { 3, 12 }, { 128, 8 }, { 248, 246 }, { 136, 182 }, { 3, 0 }, 15, 60, 0 },
{ { 3, 12 }, { 133, 0 }, { 248, 246 }, { 136, 182 }, { 3, 0 }, 15, 58, 0 },
{ { 14, 0 }, { 64, 8 }, { 118, 119 }, { 79, 24 }, { 0, 2 }, 14, 53, 0 },
{ { 14, 3 }, { 64, 0 }, { 200, 155 }, { 73, 105 }, { 0, 2 }, 14, 64, 0 },
{ { 215, 199 }, { 220, 0 }, { 173, 141 }, { 5, 5 }, { 3, 0 }, 14, 71, 0 },
{ { 215, 199 }, { 220, 0 }, { 168, 136 }, { 4, 4 }, { 3, 0 }, 14, 61, 0 },
{ { 128, 17 }, { 0, 0 }, { 246, 103 }, { 6, 23 }, { 3, 3 }, 14, 61, 0 },
{ { 128, 17 }, { 0, 9 }, { 245, 70 }, { 5, 22 }, { 2, 3 }, 14, 48, 0 },
{ { 6, 21 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 0, 0 }, 1, 48, 0 },
{ { 6, 18 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 3, 0 }, 0, 69, 0 },
{ { 6, 18 }, { 63, 0 }, { 0, 247 }, { 244, 245 }, { 0, 0 }, 1, 68, 0 },
{ { 1, 2 }, { 88, 0 }, { 103, 117 }, { 231, 7 }, { 0, 0 }, 0, 63, 0 },
{ { 65, 66 }, { 69, 8 }, { 248, 117 }, { 72, 5 }, { 0, 0 }, 0, 74, 0 },
{ { 10, 30 }, { 64, 78 }, { 224, 255 }, { 240, 5 }, { 3, 0 }, 8, 60, 0 },
{ { 10, 30 }, { 124, 82 }, { 224, 255 }, { 240, 2 }, { 3, 0 }, 8, 80, 0 },
{ { 14, 0 }, { 64, 8 }, { 122, 123 }, { 74, 27 }, { 0, 2 }, 14, 64, 0 },
{ { 14, 7 }, { 10, 64 }, { 228, 85 }, { 228, 57 }, { 3, 1 }, 6, 69, 0 },
{ { 5, 4 }, { 5, 64 }, { 249, 214 }, { 50, 165 }, { 3, 0 }, 14, 73, 0 },
{ { 2, 21 }, { 63, 0 }, { 0, 247 }, { 243, 245 }, { 3, 0 }, 8, 75, 0 },
{ { 1, 2 }, { 79, 0 }, { 250, 248 }, { 141, 181 }, { 0, 0 }, 7, 68, 0 },
{ { 0, 0 }, { 0, 0 }, { 246, 246 }, { 12, 6 }, { 0, 0 }, 4, 48, 0 },
{ { 33, 17 }, { 17, 0 }, { 163, 196 }, { 67, 34 }, { 2, 0 }, 13, 53, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 },
{ { 16, 17 }, { 68, 0 }, { 248, 243 }, { 119, 6 }, { 2, 0 }, 8, 35, 0 }
};

View file

@ -1,118 +0,0 @@
/*
Copyright (C) 1994-1995 Apogee Software, Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __linklist_h
#define __linklist_h
#ifdef __cplusplus
extern "C" {
#endif
#define NewNode(type) ((type*)SafeMalloc(sizeof(type)))
#define LL_CreateNewLinkedList(rootnode,type,next,prev) \
{ \
(rootnode) = NewNode(type); \
(rootnode)->prev = (rootnode); \
(rootnode)->next = (rootnode); \
}
#define LL_AddNode(rootnode, newnode, next, prev) \
{ \
(newnode)->next = (rootnode); \
(newnode)->prev = (rootnode)->prev; \
(rootnode)->prev->next = (newnode); \
(rootnode)->prev = (newnode); \
}
#define LL_TransferList(oldroot,newroot,next,prev) \
{ \
if ((oldroot)->prev != (oldroot)) \
{ \
(oldroot)->prev->next = (newroot); \
(oldroot)->next->prev = (newroot)->prev; \
(newroot)->prev->next = (oldroot)->next; \
(newroot)->prev = (oldroot)->prev; \
(oldroot)->next = (oldroot); \
(oldroot)->prev = (oldroot); \
} \
}
#define LL_ReverseList(root,type,next,prev) \
{ \
type *newend,*trav,*tprev; \
\
newend = (root)->next; \
for(trav = (root)->prev; trav != newend; trav = tprev) \
{ \
tprev = trav->prev; \
LL_MoveNode(trav,newend,next,prev); \
} \
}
#define LL_RemoveNode(node,next,prev) \
{ \
(node)->prev->next = (node)->next; \
(node)->next->prev = (node)->prev; \
(node)->next = (node); \
(node)->prev = (node); \
}
#define LL_SortedInsertion(rootnode,insertnode,next,prev,type,sortparm) \
{ \
type *hoya; \
\
hoya = (rootnode)->next; \
while((hoya != (rootnode)) && ((insertnode)->sortparm > hoya->sortparm)) \
{ \
hoya = hoya->next; \
} \
LL_AddNode(hoya,(insertnode),next,prev); \
}
#define LL_MoveNode(node,newroot,next,prev) \
{ \
LL_RemoveNode((node),next,prev); \
LL_AddNode((newroot),(node),next,prev); \
}
#define LL_ListEmpty(list,next,prev) \
( \
((list)->next == (list)) && \
((list)->prev == (list)) \
)
#define LL_Free(list) SafeFree(list)
#define LL_Reset(list,next,prev) (list)->next = (list)->prev = (list)
#define LL_New LL_CreateNewLinkedList
#define LL_Remove LL_RemoveNode
#define LL_Add LL_AddNode
#define LL_Empty LL_ListEmpty
#define LL_Move LL_MoveNode
#ifdef __cplusplus
};
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,70 +0,0 @@
/*
Copyright (C) 1994-1995 Apogee Software, Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/**********************************************************************
module: MIDI.H
author: James R. Dose
date: May 25, 1994
Public header for MIDI.C. Midi song file playback routines.
(c) Copyright 1994 James R. Dose. All Rights Reserved.
**********************************************************************/
#ifndef __MIDI_H
#define __MIDI_H
#include "compat.h"
#include "midifuncs.h"
enum MIDI_Errors
{
MIDI_Warning = -2,
MIDI_Error = -1,
MIDI_Ok = 0,
MIDI_NullMidiModule,
MIDI_InvalidMidiFile,
MIDI_UnknownMidiFormat,
MIDI_NoTracks,
MIDI_InvalidTrack,
MIDI_NoMemory,
MIDI_DriverError
};
#define MIDI_PASS_THROUGH 1
#define MIDI_DONT_PLAY 0
#define MIDI_MaxVolume 255
int MIDI_AllNotesOff(void);
int MIDI_Reset(void);
int MIDI_SetVolume(int volume);
int MIDI_GetVolume(void);
void MIDI_SetMidiFuncs(midifuncs *funcs);
void MIDI_SetLoopFlag(int loopflag);
void MIDI_ContinueSong(void);
void MIDI_PauseSong(void);
void MIDI_StopSong(void);
int MIDI_PlaySong(char *song, int loopflag);
void MIDI_SetTempo(int tempo);
void MIDI_Restart(void);
#endif

View file

@ -1,109 +0,0 @@
/*
Copyright (C) 2009 Jonathon Fowler <jf@jonof.id.au>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "_multivc.h"
template uint32_t MV_MixMono<uint8_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
template uint32_t MV_MixStereo<uint8_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
template uint32_t MV_MixMono<int16_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
template uint32_t MV_MixStereo<int16_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
template void MV_Reverb<int16_t>(char const *src, char * const dest, const float volume, int count);
/*
length = count of samples to mix
position = offset of starting sample in source
rate = resampling increment
volume = direct volume adjustment, 1.0 = no change
*/
// mono source, mono output
template <typename S, typename D>
uint32_t MV_MixMono(struct VoiceNode * const voice, uint32_t length)
{
auto const source = (S const *)voice->sound;
auto dest = (D *)MV_MixDestination;
uint32_t position = voice->position;
uint32_t const rate = voice->RateScale;
float const volume = voice->volume*MV_GlobalVolume;
do
{
auto const isample0 = CONVERT_LE_SAMPLE_TO_SIGNED<S, D>(source[position >> 16]);
position += rate;
*dest = MIX_SAMPLES<D>(SCALE_SAMPLE(isample0, volume*voice->LeftVolume), *dest);
dest++;
voice->LeftVolume = SMOOTH_VOLUME(voice->LeftVolume, voice->LeftVolumeDest);
}
while (--length);
MV_MixDestination = (char *)dest;
return position;
}
// mono source, stereo output
template <typename S, typename D>
uint32_t MV_MixStereo(struct VoiceNode * const voice, uint32_t length)
{
auto const source = (S const *)voice->sound;
auto dest = (D *)MV_MixDestination;
uint32_t position = voice->position;
uint32_t const rate = voice->RateScale;
float const volume = voice->volume*MV_GlobalVolume;
do
{
auto const isample0 = CONVERT_LE_SAMPLE_TO_SIGNED<S, D>(source[position >> 16]);
position += rate;
*dest = MIX_SAMPLES<D>(SCALE_SAMPLE(isample0, volume*voice->LeftVolume), *dest);
*(dest + (MV_RightChannelOffset / sizeof(*dest)))
= MIX_SAMPLES<D>(SCALE_SAMPLE(isample0, volume*voice->RightVolume), *(dest + (MV_RightChannelOffset / sizeof(*dest))));
dest += 2;
voice->LeftVolume = SMOOTH_VOLUME(voice->LeftVolume, voice->LeftVolumeDest);
voice->RightVolume = SMOOTH_VOLUME(voice->RightVolume, voice->RightVolumeDest);
}
while (--length);
MV_MixDestination = (char *)dest;
return position;
}
template <typename T>
void MV_Reverb(char const *src, char * const dest, const float volume, int count)
{
auto input = (T const *)src;
auto output = (T *)dest;
do
{
auto const isample0 = CONVERT_SAMPLE_TO_SIGNED<T>(*input++);
*output++ = CONVERT_SAMPLE_FROM_SIGNED<T>(SCALE_SAMPLE(isample0, volume));
}
while (--count > 0);
}

View file

@ -1,96 +0,0 @@
/*
Copyright (C) 2009 Jonathon Fowler <jf@jonof.id.au>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "_multivc.h"
template uint32_t MV_MixMonoStereo<uint8_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
template uint32_t MV_MixStereoStereo<uint8_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
template uint32_t MV_MixMonoStereo<int16_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
template uint32_t MV_MixStereoStereo<int16_t, int16_t>(struct VoiceNode * const voice, uint32_t length);
/*
length = count of samples to mix
position = offset of starting sample in source
rate = resampling increment
volume = direct volume adjustment, 1.0 = no change
*/
// stereo source, mono output
template <typename S, typename D>
uint32_t MV_MixMonoStereo(struct VoiceNode * const voice, uint32_t length)
{
auto const source = (S const *)voice->sound;
auto dest = (D *)MV_MixDestination;
uint32_t position = voice->position;
uint32_t const rate = voice->RateScale;
float const volume = voice->volume*MV_GlobalVolume;
do
{
auto const isample0 = CONVERT_LE_SAMPLE_TO_SIGNED<S, D>(source[(position >> 16) << 1]);
auto const isample1 = CONVERT_LE_SAMPLE_TO_SIGNED<S, D>(source[((position >> 16) << 1) + 1]);
position += rate;
*dest = MIX_SAMPLES<D>((SCALE_SAMPLE((isample0 + isample1) >> 1, volume*voice->LeftVolume)), *dest);
dest++;
voice->LeftVolume = SMOOTH_VOLUME(voice->LeftVolume, voice->LeftVolumeDest);
}
while (--length);
MV_MixDestination = (char *)dest;
return position;
}
// stereo source, stereo output
template <typename S, typename D>
uint32_t MV_MixStereoStereo(struct VoiceNode * const voice, uint32_t length)
{
auto const source = (S const *)voice->sound;
auto dest = (D *)MV_MixDestination;
uint32_t position = voice->position;
uint32_t const rate = voice->RateScale;
float const volume = voice->volume*MV_GlobalVolume;
do
{
auto const isample0 = CONVERT_LE_SAMPLE_TO_SIGNED<S, D>(source[(position >> 16) << 1]);
auto const isample1 = CONVERT_LE_SAMPLE_TO_SIGNED<S, D>(source[((position >> 16) << 1) + 1]);
position += rate;
*dest = MIX_SAMPLES<D>(SCALE_SAMPLE(isample0, volume*voice->LeftVolume), *dest);
*(dest + (MV_RightChannelOffset / sizeof(*dest)))
= MIX_SAMPLES<D>(SCALE_SAMPLE(isample1, volume*voice->RightVolume), *(dest + (MV_RightChannelOffset / sizeof(*dest))));
dest += 2;
voice->LeftVolume = SMOOTH_VOLUME(voice->LeftVolume, voice->LeftVolumeDest);
voice->RightVolume = SMOOTH_VOLUME(voice->RightVolume, voice->RightVolumeDest);
}
while (--length);
MV_MixDestination = (char *)dest;
return position;
}

View file

@ -1,885 +0,0 @@
/*
Copyright (C) 1994-1995 Apogee Software, Ltd.
Copyright (C) 2015 EDuke32 developers
Copyright (C) 2015 Voidpoint, LLC
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**********************************************************************
module: MULTIVOC.C
author: James R. Dose
date: December 20, 1993
Routines to provide multichannel digitized sound playback for
Sound Blaster compatible sound cards.
(c) Copyright 1993 James R. Dose. All Rights Reserved.
**********************************************************************/
#include "multivoc.h"
#include "_multivc.h"
#include "baselayer.h"
#include "compat.h"
#include "drivers.h"
#include "fx_man.h"
#include "linklist.h"
#include "osd.h"
#include "pitch.h"
#include "pragmas.h"
static void MV_StopVoice(VoiceNode *voice);
static void MV_ServiceVoc(void);
static VoiceNode *MV_GetVoice(int handle);
static int MV_ReverbLevel;
static int MV_ReverbDelay;
static float MV_ReverbVolume;
Pan MV_PanTable[MV_NUMPANPOSITIONS][MV_MAXVOLUME + 1];
int MV_Installed;
static int MV_TotalVolume = MV_MAXTOTALVOLUME;
static int MV_MaxVoices = 1;
int MV_BufferSize = MV_MIXBUFFERSIZE;
static int MV_BufferLength;
static int MV_NumberOfBuffers = MV_NUMBEROFBUFFERS;
static int MV_Channels = 1;
static int MV_ReverseStereo;
int MV_MixRate;
static int MV_BufferEmpty[MV_NUMBEROFBUFFERS];
char *MV_MixBuffer[(MV_NUMBEROFBUFFERS << 1) + 1];
static VoiceNode *MV_Voices;
static VoiceNode VoiceList;
static VoiceNode VoicePool;
static int MV_MixPage;
void (*MV_Printf)(const char *fmt, ...) = OSD_Printf;
static void (*MV_CallBackFunc)(intptr_t);
char *MV_MixDestination;
int MV_SampleSize = 1;
int MV_RightChannelOffset;
int MV_ErrorCode = MV_NotInstalled;
float MV_GlobalVolume = 1.f;
float MV_VolumeSmooth = 1.f;
int MV_Locked;
char *MV_MusicBuffer;
static void (*MV_MusicCallback)(void);
static int MV_MixMusic = FALSE;
static bool MV_Mix(VoiceNode * const voice, int const buffer)
{
if (voice->length == 0 && voice->GetSound(voice) != KeepPlaying)
return false;
float const gv = MV_GlobalVolume;
if (voice->priority == FX_MUSIC_PRIORITY)
MV_GlobalVolume = 1.f;
int length = MV_MIXBUFFERSIZE;
uint32_t bufsiz = voice->FixedPointBufferSize;
uint32_t const rate = voice->RateScale;
MV_MixDestination = MV_MixBuffer[buffer];
// Add this voice to the mix
do
{
int mixlen = length;
uint32_t const position = voice->position;
uint32_t const voclen = voice->length;
// Check if the last sample in this buffer would be
// beyond the length of the sample block
if ((position + bufsiz) >= voclen)
{
if (position >= voclen)
{
voice->GetSound(voice);
break;
}
mixlen = (voclen - position + rate - voice->channels) / rate;
}
voice->position = voice->mix(voice, mixlen);
length -= mixlen;
if (voice->position >= voclen)
{
// Get the next block of sound
if (voice->GetSound(voice) == NoMoreData)
{
MV_GlobalVolume = gv;
return false;
}
// Get the position of the last sample in the buffer
if (length > (voice->channels - 1))
bufsiz = voice->RateScale * (length - voice->channels);
}
} while (length > 0);
MV_GlobalVolume = gv;
return true;
}
void MV_PlayVoice(VoiceNode *voice)
{
MV_Lock();
LL::SortedInsert(&VoiceList, voice, &VoiceNode::priority);
voice->LeftVolume = voice->LeftVolumeDest;
voice->RightVolume = voice->RightVolumeDest;
MV_Unlock();
}
static void MV_CleanupVoice(VoiceNode *voice)
{
if (MV_CallBackFunc)
MV_CallBackFunc(voice->callbackval);
switch (voice->wavetype)
{
case FMT_VORBIS: MV_ReleaseVorbisVoice(voice); break;
//case FMT_ZMUSIC: MV_ReleaseZMusicVoice(voice); break;
default: break;
}
voice->handle = 0;
}
static void MV_StopVoice(VoiceNode *voice)
{
MV_CleanupVoice(voice);
MV_Lock();
// move the voice from the play list to the free list
LL::Move(voice, &VoicePool);
MV_Unlock();
}
/*---------------------------------------------------------------------
JBF: no synchronisation happens inside MV_ServiceVoc nor the
supporting functions it calls. This would cause a deadlock
between the mixer thread in the driver vs the nested
locking in the user-space functions of MultiVoc. The call
to MV_ServiceVoc is synchronised in the driver.
---------------------------------------------------------------------*/
static void MV_ServiceVoc(void)
{
// Toggle which buffer we'll mix next
++MV_MixPage &= MV_NumberOfBuffers-1;
if (MV_ReverbLevel == 0)
{
if (!MV_BufferEmpty[MV_MixPage])
{
Bmemset(MV_MixBuffer[MV_MixPage], 0, MV_BufferSize);
MV_BufferEmpty[ MV_MixPage ] = TRUE;
}
}
else
{
char const *const end = MV_MixBuffer[0] + MV_BufferLength;
char * dest = MV_MixBuffer[MV_MixPage];
char const * source = MV_MixBuffer[MV_MixPage] - MV_ReverbDelay;
if (source < MV_MixBuffer[ 0 ])
source += MV_BufferLength;
int length = MV_BufferSize;
do
{
int const count = (source + length > end) ? (end - source) : length;
MV_Reverb<int16_t>(source, dest, MV_ReverbVolume, count >> 1);
// if we go through the loop again, it means that we've wrapped around the buffer
source = MV_MixBuffer[ 0 ];
dest += count;
length -= count;
} while (length > 0);
}
if (VoiceList.next && VoiceList.next != &VoiceList)
{
VoiceNode *voice = VoiceList.next;
VoiceNode *next;
do
{
next = voice->next;
if (voice->Paused)
continue;
MV_BufferEmpty[ MV_MixPage ] = FALSE;
// Is this voice done?
if (!MV_Mix(voice, MV_MixPage))
{
MV_CleanupVoice(voice);
LL::Move(voice, &VoicePool);
}
}
while ((voice = next) != &VoiceList);
}
Bmemcpy(MV_MixBuffer[MV_MixPage+MV_NumberOfBuffers], MV_MixBuffer[MV_MixPage], MV_BufferSize);
if (MV_MixMusic)
{
MV_MusicCallback();
int16_t *source = (int16_t*)MV_MusicBuffer;
int16_t *dest = (int16_t*)MV_MixBuffer[MV_MixPage+MV_NumberOfBuffers];
for (int32_t i = 0; i < MV_BufferSize>>2; i++)
{
int32_t sl = *source++;
int32_t sr = *source++;
*dest = clamp(*dest+sl,INT16_MIN, INT16_MAX);
dest++;
*dest = clamp(*dest+sr,INT16_MIN, INT16_MAX);
dest++;
}
}
}
static VoiceNode *MV_GetVoice(int handle)
{
if (handle < MV_MINVOICEHANDLE || handle > MV_MaxVoices)
{
//MV_Printf("MV_GetVoice(): bad handle (%d)!\n", handle);
return nullptr;
}
MV_Lock();
for (VoiceNode *voice = VoiceList.next; voice != &VoiceList; voice = voice->next)
{
if (handle == voice->handle)
{
MV_Unlock();
return voice;
}
}
MV_Unlock();
MV_SetErrorCode(MV_VoiceNotFound);
return nullptr;
}
VoiceNode *MV_BeginService(int handle)
{
if (!MV_Installed)
return nullptr;
VoiceNode *voice = MV_GetVoice(handle);
if (voice == nullptr)
{
MV_SetErrorCode(MV_VoiceNotFound);
return nullptr;
}
MV_Lock();
return voice;
}
static inline void MV_EndService(void) { MV_Unlock(); }
int MV_VoicePlaying(int handle)
{
return (MV_Installed && MV_GetVoice(handle)) ? TRUE : FALSE;
}
int MV_KillAllVoices(void)
{
if (!MV_Installed)
return MV_Error;
MV_Lock();
if (&VoiceList == VoiceList.next)
{
MV_Unlock();
return MV_Ok;
}
VoiceNode * voice = VoiceList.prev;
// Remove all the voices from the list
while (voice != &VoiceList)
{
if (voice->priority == MV_MUSIC_PRIORITY)
{
voice = voice->prev;
continue;
}
MV_Kill(voice->handle);
voice = VoiceList.prev;
}
MV_Unlock();
return MV_Ok;
}
int MV_Kill(int handle)
{
VoiceNode *voice = MV_BeginService(handle);
if (voice == nullptr)
return MV_Error;
MV_StopVoice(voice);
MV_EndService();
return MV_Ok;
}
int MV_VoicesPlaying(void)
{
if (!MV_Installed)
return 0;
MV_Lock();
int NumVoices = 0;
for (VoiceNode *voice = VoiceList.next; voice != &VoiceList; voice = voice->next)
NumVoices++;
MV_Unlock();
return NumVoices;
}
VoiceNode *MV_AllocVoice(int priority)
{
VoiceNode *voice;
MV_Lock();
// Check if we have any free voices
if (LL::Empty(&VoicePool))
{
// check if we have a higher priority than a voice that is playing.
for (auto node = voice = VoiceList.next; node != &VoiceList; node = node->next)
{
if (node->priority < voice->priority)
voice = node;
}
if (priority >= voice->priority && voice != &VoiceList && voice->handle >= MV_MINVOICEHANDLE)
MV_Kill(voice->handle);
if (LL::Empty(&VoicePool))
{
// No free voices
MV_Unlock();
return nullptr;
}
}
voice = VoicePool.next;
LL::Remove(voice);
MV_Unlock();
int vhan = MV_MINVOICEHANDLE;
// Find a free voice handle
do
{
if (++vhan < MV_MINVOICEHANDLE || vhan > MV_MaxVoices)
vhan = MV_MINVOICEHANDLE;
} while (MV_VoicePlaying(vhan));
voice->handle = vhan;
return voice;
}
int MV_VoiceAvailable(int priority)
{
// Check if we have any free voices
if (!LL::Empty(&VoicePool))
return TRUE;
MV_Lock();
VoiceNode *voice;
// check if we have a higher priority than a voice that is playing.
for (auto node = voice = VoiceList.next; node != &VoiceList; node = node->next)
{
if (node->priority < voice->priority)
voice = node;
}
if ((voice == &VoiceList) || (priority < voice->priority))
{
MV_Unlock();
return FALSE;
}
MV_Unlock();
return TRUE;
}
void MV_SetVoicePitch(VoiceNode *voice, uint32_t rate, int pitchoffset)
{
voice->SamplingRate = rate;
voice->PitchScale = PITCH_GetScale(pitchoffset);
voice->RateScale = divideu32(rate * voice->PitchScale, MV_MixRate);
// Multiply by MV_MIXBUFFERSIZE - 1
voice->FixedPointBufferSize = (voice->RateScale * MV_MIXBUFFERSIZE) -
voice->RateScale;
}
int MV_SetPitch(int handle, int pitchoffset)
{
VoiceNode *voice = MV_BeginService(handle);
if (voice == nullptr)
return MV_Error;
MV_SetVoicePitch(voice, voice->SamplingRate, pitchoffset);
MV_EndService();
return MV_Ok;
}
int MV_SetFrequency(int handle, int frequency)
{
VoiceNode *voice = MV_BeginService(handle);
if (voice == nullptr)
return MV_Error;
MV_SetVoicePitch(voice, frequency, 0);
MV_EndService();
return MV_Ok;
}
/*---------------------------------------------------------------------
Function: MV_SetVoiceMixMode
Selects which method should be used to mix the voice.
16Bit 16Bit | 8Bit 16Bit 8Bit 16Bit |
Mono Ster | Mono Mono Ster Ster | Mixer
Out Out | In In In In |
----------------------+---------------------------+-------------
X | X | MixMono<int16_t, int16_t>
X | X | MixMono<uint8_t, int16_t>
X | X | MixStereo<int16_t, int16_t>
X | X | MixStereo<uint8_t, int16_t>
----------------------+---------------------------+-------------
X | X | MixStereoStereo<int16_t, int16_t>
X | X | MixStereoStereo<uint8_t, int16_t>
X | X | MixMonoStereo<int16_t, int16_t>
X | X | MixMonoStereo<uint8_t, int16_t>
---------------------------------------------------------------------*/
void MV_SetVoiceMixMode(VoiceNode *voice)
{
int type = T_DEFAULT;
if (MV_Channels == 1)
type |= T_MONO;
if (voice->bits == 16)
type |= T_16BITSOURCE;
if (voice->channels == 2)
type |= T_STEREOSOURCE;
// stereo look-up table
static constexpr decltype(voice->mix) mixslut[]
= { MV_MixStereo<uint8_t, int16_t>, MV_MixMono<uint8_t, int16_t>, MV_MixStereo<int16_t, int16_t>, MV_MixMono<int16_t, int16_t>,
MV_MixStereoStereo<uint8_t, int16_t>, MV_MixMonoStereo<uint8_t, int16_t>, MV_MixStereoStereo<int16_t, int16_t>, MV_MixMonoStereo<int16_t, int16_t> };
voice->mix = mixslut[type];
}
void MV_SetVoiceVolume(VoiceNode *voice, int vol, int left, int right, float volume)
{
if (MV_Channels == 1)
left = right = vol;
else if (MV_ReverseStereo)
swap(&left, &right);
voice->LeftVolumeDest = float(left)*(1.f/MV_MAXTOTALVOLUME);
voice->RightVolumeDest = float(right)*(1.f/MV_MAXTOTALVOLUME);
voice->volume = volume;
MV_SetVoiceMixMode(voice);
}
int MV_PauseVoice(int handle, int pause)
{
VoiceNode *voice = MV_BeginService(handle);
if (voice == nullptr)
return MV_Error;
voice->Paused = pause;
MV_EndService();
return MV_Ok;
}
int MV_EndLooping(int handle)
{
VoiceNode *voice = MV_BeginService(handle);
if (voice == nullptr)
return MV_Error;
voice->LoopCount = 0;
voice->LoopStart = nullptr;
voice->LoopEnd = nullptr;
MV_EndService();
return MV_Ok;
}
int MV_SetPan(int handle, int vol, int left, int right)
{
VoiceNode *voice = MV_BeginService(handle);
if (voice == nullptr)
return MV_Error;
MV_SetVoiceVolume(voice, vol, left, right, voice->volume);
MV_EndService();
return MV_Ok;
}
int MV_Pan3D(int handle, int angle, int distance)
{
if (distance < 0)
{
distance = -distance;
angle += MV_NUMPANPOSITIONS / 2;
}
int const volume = MIX_VOLUME(distance);
angle &= MV_MAXPANPOSITION;
return MV_SetPan(handle, max(0, 255 - distance),
MV_PanTable[ angle ][ volume ].left,
MV_PanTable[ angle ][ volume ].right);
}
void MV_SetReverb(int reverb)
{
MV_ReverbLevel = MIX_VOLUME(reverb);
MV_ReverbVolume = float(MV_ReverbLevel)*(1.f/MV_MAXVOLUME);
}
int MV_GetMaxReverbDelay(void) { return MV_MIXBUFFERSIZE * MV_NumberOfBuffers; }
int MV_GetReverbDelay(void) { return tabledivide32(MV_ReverbDelay, MV_SampleSize); }
void MV_SetReverbDelay(int delay)
{
MV_ReverbDelay = max(MV_MIXBUFFERSIZE, min(delay, MV_GetMaxReverbDelay())) * MV_SampleSize;
}
static int MV_SetMixMode(int numchannels)
{
if (!MV_Installed)
return MV_Error;
MV_Channels = 1 + (numchannels == 2);
MV_SampleSize = sizeof(int8_t) * MV_Channels * 2;
MV_BufferSize = MV_MIXBUFFERSIZE * MV_SampleSize;
MV_NumberOfBuffers = tabledivide32(MV_TOTALBUFFERSIZE, MV_BufferSize);
Bassert(isPow2(MV_NumberOfBuffers));
MV_BufferLength = MV_TOTALBUFFERSIZE;
MV_RightChannelOffset = MV_SampleSize >> 1;
return MV_Ok;
}
static int MV_StartPlayback(void)
{
// Initialize the buffers
Bmemset(MV_MixBuffer[0], 0, MV_TOTALBUFFERSIZE << 1);
for (int buffer = 0; buffer < MV_NumberOfBuffers; buffer++)
MV_BufferEmpty[buffer] = TRUE;
MV_MixPage = 1;
if (SoundDriver_PCM_BeginPlayback(MV_MixBuffer[MV_NumberOfBuffers], MV_BufferSize, MV_NumberOfBuffers, MV_ServiceVoc) != MV_Ok)
return MV_SetErrorCode(MV_DriverError);
return MV_Ok;
}
static void MV_StopPlayback(void)
{
SoundDriver_PCM_StopPlayback();
// Make sure all callbacks are done.
MV_Lock();
for (VoiceNode *voice = VoiceList.next, *next; voice != &VoiceList; voice = next)
{
next = voice->next;
MV_StopVoice(voice);
}
MV_Unlock();
}
static void MV_CalcPanTable(void)
{
const int HalfAngle = MV_NUMPANPOSITIONS / 2;
const int QuarterAngle = HalfAngle / 2;
for (int distance = 0; distance <= MV_MAXVOLUME; distance++)
{
const int level = (255 * (MV_MAXVOLUME - distance)) / MV_MAXVOLUME;
for (int angle = 0; angle <= QuarterAngle; angle++)
{
const int ramp = level - (level * angle) / QuarterAngle;
MV_PanTable[angle][distance].left = ramp;
MV_PanTable[angle][distance].right = level;
MV_PanTable[HalfAngle - angle][distance].left = ramp;
MV_PanTable[HalfAngle - angle][distance].right = level;
MV_PanTable[HalfAngle + angle][distance].left = level;
MV_PanTable[HalfAngle + angle][distance].right = ramp;
MV_PanTable[MV_MAXPANPOSITION - angle][distance].left = level;
MV_PanTable[MV_MAXPANPOSITION - angle][distance].right = ramp;
}
}
}
void MV_SetVolume(int volume)
{
MV_TotalVolume = min(max(0, volume), MV_MAXTOTALVOLUME);
MV_GlobalVolume = (float)volume / 255.f;
// MV_CalcVolume(MV_TotalVolume);
}
int MV_GetVolume(void) { return MV_TotalVolume; }
void MV_SetCallBack(void (*function)(intptr_t)) { MV_CallBackFunc = function; }
void MV_SetReverseStereo(int setting) { MV_ReverseStereo = setting; }
int MV_GetReverseStereo(void) { return MV_ReverseStereo; }
int MV_Init(int soundcard, int MixRate, int Voices, int numchannels, void *initdata)
{
if (MV_Installed)
MV_Shutdown();
MV_SetErrorCode(MV_Ok);
// MV_TotalMemory + 2: FIXME, see valgrind_errors.log
int const totalmem = Voices * sizeof(VoiceNode) + (MV_TOTALBUFFERSIZE<<1) + (MV_MIXBUFFERSIZE<<2) + 2;
char *ptr = (char *) Xaligned_alloc(16, totalmem);
if (!ptr)
return MV_SetErrorCode(MV_NoMem);
Bmemset(ptr, 0, totalmem);
MV_Voices = (VoiceNode *)ptr;
ptr += Voices * sizeof(VoiceNode);
MV_MaxVoices = Voices;
LL::Reset((VoiceNode*) &VoiceList);
LL::Reset((VoiceNode*) &VoicePool);
for (int index = 0; index < Voices; index++)
LL::Insert(&VoicePool, &MV_Voices[index]);
MV_SetReverseStereo(FALSE);
ASS_PCMSoundDriver = soundcard;
// Initialize the sound card
if (SoundDriver_PCM_Init(&MixRate, &numchannels, initdata) != MV_Ok)
MV_SetErrorCode(MV_DriverError);
if (MV_ErrorCode != MV_Ok)
{
ALIGNED_FREE_AND_NULL(MV_Voices);
return MV_Error;
}
MV_Installed = TRUE;
MV_CallBackFunc = nullptr;
MV_ReverbLevel = 0;
MV_ReverbVolume = 0.f;
// Set the sampling rate
MV_MixRate = MixRate;
// Set Mixer to play stereo digitized sound
MV_SetMixMode(numchannels);
MV_ReverbDelay = MV_BufferSize * 3;
// Make sure we don't cross a physical page
MV_MixBuffer[ MV_NumberOfBuffers<<1 ] = ptr;
for (int buffer = 0; buffer < MV_NumberOfBuffers<<1; buffer++)
{
MV_MixBuffer[ buffer ] = ptr;
ptr += MV_BufferSize;
}
MV_MusicBuffer = ptr;
// Calculate pan table
MV_CalcPanTable();
MV_VolumeSmooth = 1.f-powf(0.1f, 30.f/MixRate);
// Start the playback engine
if (MV_StartPlayback() != MV_Ok)
{
// Preserve error code while we shutdown.
int status = MV_ErrorCode;
MV_Shutdown();
return MV_SetErrorCode(status);
}
return MV_Ok;
}
int MV_Shutdown(void)
{
if (!MV_Installed)
return MV_Ok;
MV_KillAllVoices();
MV_Installed = FALSE;
// Stop the sound playback engine
MV_StopPlayback();
// Shutdown the sound card
SoundDriver_PCM_Shutdown();
// Free any voices we allocated
ALIGNED_FREE_AND_NULL(MV_Voices);
LL::Reset((VoiceNode*) &VoiceList);
LL::Reset((VoiceNode*) &VoicePool);
MV_MaxVoices = 1;
// Release the descriptor from our mix buffer
for (int buffer = 0; buffer < MV_NUMBEROFBUFFERS<<1; buffer++)
MV_MixBuffer[ buffer ] = nullptr;
MV_SetErrorCode(MV_NotInstalled);
return MV_Ok;
}
void MV_HookMusicRoutine(void(*callback)(void))
{
MV_Lock();
MV_MusicCallback = callback;
MV_MixMusic = TRUE;
MV_Unlock();
}
void MV_UnhookMusicRoutine(void)
{
if (MV_MusicCallback)
{
MV_Lock();
MV_MusicCallback = nullptr;
MV_MixMusic = FALSE;
MV_Unlock();
}
}
MV_MusicRoutineBuffer MV_GetMusicRoutineBuffer()
{
return MV_MusicRoutineBuffer{ MV_MusicBuffer, MV_BufferSize };
}
const char *loopStartTags[loopStartTagCount] = { "LOOP_START", "LOOPSTART", "LOOP" };
const char *loopEndTags[loopEndTagCount] = { "LOOP_END", "LOOPEND" };
const char *loopLengthTags[loopLengthTagCount] = { "LOOP_LENGTH", "LOOPLENGTH" };
const char *MV_ErrorString(int ErrorNumber)
{
switch (ErrorNumber)
{
case MV_Error:
return MV_ErrorString(MV_ErrorCode);
case MV_Ok:
return "Multivoc ok.";
case MV_NotInstalled:
return "Multivoc not installed.";
case MV_DriverError:
return SoundDriver_PCM_ErrorString(SoundDriver_PCM_GetError());
case MV_NoVoices:
return "No free voices available to Multivoc.";
case MV_NoMem:
return "Out of memory in Multivoc.";
case MV_VoiceNotFound:
return "No voice with matching handle found.";
case MV_InvalidFile:
return "Invalid file passed in to Multivoc.";
default:
return "Unknown Multivoc error code.";
}
}

View file

@ -1,147 +0,0 @@
//-------------------------------------------------------------------------
/*
Copyright (C) 2010-2019 EDuke32 developers and contributors
Copyright (C) 2019 Nuke.YKT
This file is part of NBlood.
NBlood is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
//-------------------------------------------------------------------------
#include "music.h"
#include "compat.h"
#include "drivers.h"
#include "midi.h"
#include "multivoc.h"
#include "sndcards.h"
int MUSIC_ErrorCode = MUSIC_Ok;
static midifuncs MUSIC_MidiFunctions;
#define MUSIC_SetErrorCode(status) MUSIC_ErrorCode = (status);
const char *MUSIC_ErrorString(int ErrorNumber)
{
const char *ErrorString;
switch (ErrorNumber)
{
case MUSIC_Warning:
case MUSIC_Error: ErrorString = MUSIC_ErrorString(MUSIC_ErrorCode); break;
case MUSIC_Ok: ErrorString = "Music ok."; break;
case MUSIC_MidiError: ErrorString = "Error playing MIDI file."; break;
default: ErrorString = "Unknown Music error code."; break;
}
return ErrorString;
}
int MUSIC_Init(int SoundCard)
{
int detected = 0;
if (SoundCard == ASS_AutoDetect)
{
redetect:
detected++;
SoundCard = ASS_OPL3;
}
if (SoundCard < 0 || SoundCard >= ASS_NumSoundCards)
{
failed:
MV_Printf("failed!\n");
MUSIC_ErrorCode = MUSIC_MidiError;
return MUSIC_Error;
}
if (!SoundDriver_IsMIDISupported(SoundCard))
{
MV_Printf("Couldn't init %s\n", SoundDriver_GetName(SoundCard));
if (detected < 2)
goto redetect;
goto failed;
}
ASS_MIDISoundDriver = SoundCard;
int status = SoundDriver_MIDI_Init(&MUSIC_MidiFunctions);
if (status != MUSIC_Ok)
{
if (detected < 2)
goto redetect;
goto failed;
}
MV_Printf("%s\n", SoundDriver_GetName(SoundCard));
MIDI_SetMidiFuncs(&MUSIC_MidiFunctions);
return MUSIC_Ok;
}
int MUSIC_Shutdown(void)
{
MIDI_StopSong();
return MUSIC_Ok;
}
void MUSIC_SetVolume(int volume) { MIDI_SetVolume(min(max(0, volume), 255)); }
int MUSIC_GetVolume(void) { return MIDI_GetVolume(); }
void MUSIC_SetLoopFlag(int loopflag) { MIDI_SetLoopFlag(loopflag); }
void MUSIC_Continue(void) { MIDI_ContinueSong(); }
void MUSIC_Pause(void) { MIDI_PauseSong(); }
int MUSIC_StopSong(void)
{
MIDI_StopSong();
MUSIC_SetErrorCode(MUSIC_Ok);
return MUSIC_Ok;
}
int MUSIC_PlaySong(char *song, int songsize, int loopflag, const char *fn /*= nullptr*/)
{
UNREFERENCED_PARAMETER(songsize);
UNREFERENCED_PARAMETER(fn);
MUSIC_SetErrorCode(MUSIC_Ok)
if (MIDI_PlaySong(song, loopflag) != MIDI_Ok)
{
MUSIC_SetErrorCode(MUSIC_MidiError);
return MUSIC_Warning;
}
return MUSIC_Ok;
}
void MUSIC_Update(void)
{
}

File diff suppressed because it is too large Load diff

View file

@ -1,84 +0,0 @@
/*
Copyright (C) 1994-1995 Apogee Software, Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**********************************************************************
module: PITCH.C
author: James R. Dose
date: June 14, 1993
Routines for pitch scaling.
(c) Copyright 1993 James R. Dose. All Rights Reserved.
**********************************************************************/
#include "compat.h"
#include "pitch.h"
#define MAXDETUNE 50
static uint32_t PitchTable[12][MAXDETUNE];
/*---------------------------------------------------------------------
Function: PITCH_Init
Initializes pitch table.
---------------------------------------------------------------------*/
void PITCH_Init(void)
{
for (int note = 0; note < 12; note++)
for (int detune = 0; detune < MAXDETUNE; detune++)
PitchTable[note][detune] = (uint32_t) (65536.f * powf(2.f, (note * MAXDETUNE + detune) / (12.f * MAXDETUNE)));
}
/*---------------------------------------------------------------------
Function: PITCH_GetScale
Returns a fixed-point value to scale number the specified amount.
---------------------------------------------------------------------*/
uint32_t PITCH_GetScale(int const pitchoffset)
{
static bool bInitialized;
if (!bInitialized)
{
PITCH_Init();
bInitialized = true;
}
if (pitchoffset == 0)
return PitchTable[0][0];
int noteshift = pitchoffset % 1200;
if (noteshift < 0)
noteshift += 1200;
int const note = noteshift / 100;
int const detune = (noteshift % 100) / (100 / MAXDETUNE);
int const oshift = (pitchoffset - noteshift) / 1200;
auto const &scale = PitchTable[note][detune];
return (oshift < 0) ? (scale >> -oshift) : (scale << oshift);
}

View file

@ -1,37 +0,0 @@
/*
Copyright (C) 1994-1995 Apogee Software, Ltd.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**********************************************************************
module: PITCH.H
author: James R. Dose
date: June 14, 1994
Public header for PITCH.C
(c) Copyright 1994 James R. Dose. All Rights Reserved.
**********************************************************************/
#ifndef PITCH_H_
#define PITCH_H_
#include <inttypes.h>
uint32_t PITCH_GetScale(int pitchoffset);
#endif

View file

@ -1,472 +0,0 @@
/*
Copyright (C) 2009 Jonathon Fowler <jf@jonof.id.au>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* OggVorbis source support for MultiVoc
*/
#include "compat.h"
#include "pragmas.h"
#ifdef HAVE_VORBIS
#include "pitch.h"
#include "multivoc.h"
#include "_multivc.h"
#define OV_EXCLUDE_STATIC_CALLBACKS
#if defined __APPLE__
# include <vorbis/vorbisfile.h>
#elif defined GEKKO
# define USING_TREMOR
# include <tremor/ivorbisfile.h>
#else
# include "vorbis/vorbisfile.h"
#endif
#define BLOCKSIZE MV_MIXBUFFERSIZE
typedef struct {
void * ptr;
size_t length;
size_t pos;
OggVorbis_File vf;
char block[BLOCKSIZE];
int lastbitstream;
} vorbis_data;
// designed with multiple calls in mind
static void MV_GetVorbisCommentLoops(VoiceNode *voice, vorbis_comment *vc)
{
const char *vc_loopstart = nullptr;
const char *vc_loopend = nullptr;
const char *vc_looplength = nullptr;
for (int comment = 0; comment < vc->comments; ++comment)
{
auto entry = (const char *)vc->user_comments[comment];
if (entry != nullptr && entry[0] != '\0')
{
const char *value = Bstrchr(entry, '=');
if (!value)
continue;
const size_t field = value - entry;
value += 1;
for (int t = 0; t < loopStartTagCount && vc_loopstart == nullptr; ++t)
{
auto tag = loopStartTags[t];
if (field == Bstrlen(tag) && Bstrncasecmp(entry, tag, field) == 0)
vc_loopstart = value;
}
for (int t = 0; t < loopEndTagCount && vc_loopend == nullptr; ++t)
{
auto tag = loopEndTags[t];
if (field == Bstrlen(tag) && Bstrncasecmp(entry, tag, field) == 0)
vc_loopend = value;
}
for (int t = 0; t < loopLengthTagCount && vc_looplength == nullptr; ++t)
{
auto tag = loopLengthTags[t];
if (field == Bstrlen(tag) && Bstrncasecmp(entry, tag, field) == 0)
vc_looplength = value;
}
}
}
if (vc_loopstart != nullptr)
{
const ogg_int64_t ov_loopstart = Batol(vc_loopstart);
if (ov_loopstart >= 0) // a loop starting at 0 is valid
{
voice->LoopStart = (const char *) (intptr_t) ov_loopstart;
voice->LoopSize = 1;
}
}
if (vc_loopend != nullptr)
{
if (voice->LoopSize > 0)
{
const ogg_int64_t ov_loopend = Batol(vc_loopend);
if (ov_loopend > 0) // a loop ending at 0 is invalid
voice->LoopEnd = (const char *) (intptr_t) ov_loopend;
}
}
if (vc_looplength != nullptr)
{
if (voice->LoopSize > 0 && voice->LoopEnd == 0)
{
const ogg_int64_t ov_looplength = Batol(vc_looplength);
if (ov_looplength > 0) // a loop of length 0 is invalid
voice->LoopEnd = (const char *) ((intptr_t) ov_looplength + (intptr_t) voice->LoopStart);
}
}
}
// callbacks
static size_t read_vorbis(void *ptr, size_t size, size_t nmemb, void *datasource)
{
auto vorb = (vorbis_data *)datasource;
errno = 0;
if (vorb->length == vorb->pos)
return 0;
int nread = 0;
for (; nmemb > 0; nmemb--, nread++)
{
int bytes = vorb->length - vorb->pos;
if ((signed)size < bytes)
bytes = (int)size;
memcpy(ptr, (uint8_t *)vorb->ptr + vorb->pos, bytes);
vorb->pos += bytes;
ptr = (uint8_t *)ptr + bytes;
if (vorb->length == vorb->pos)
{
nread++;
break;
}
}
return nread;
}
static int seek_vorbis(void *datasource, ogg_int64_t offset, int whence)
{
auto vorb = (vorbis_data *)datasource;
switch (whence)
{
case SEEK_SET: vorb->pos = 0; break;
case SEEK_CUR: break;
case SEEK_END: vorb->pos = vorb->length; break;
}
vorb->pos += offset;
if (vorb->pos > vorb->length)
vorb->pos = vorb->length;
return vorb->pos;
}
static int close_vorbis(void *datasource)
{
UNREFERENCED_PARAMETER(datasource);
return 0;
}
static long tell_vorbis(void *datasource)
{
auto vorb = (vorbis_data *)datasource;
return vorb->pos;
}
static ov_callbacks vorbis_callbacks = { read_vorbis, seek_vorbis, close_vorbis, tell_vorbis };
int MV_GetVorbisPosition(VoiceNode *voice)
{
auto vd = (vorbis_data *) voice->rawdataptr;
return ov_pcm_tell(&vd->vf);
}
void MV_SetVorbisPosition(VoiceNode *voice, int position)
{
auto vd = (vorbis_data *) voice->rawdataptr;
ov_pcm_seek(&vd->vf, position);
}
/*---------------------------------------------------------------------
Function: MV_GetNextVorbisBlock
Controls playback of OggVorbis data
---------------------------------------------------------------------*/
static playbackstatus MV_GetNextVorbisBlock(VoiceNode *voice)
{
int bitstream;
int bytesread = 0;
auto vd = (vorbis_data *)voice->rawdataptr;
do
{
#ifdef USING_TREMOR
int bytes = ov_read(&vd->vf, vd->block + bytesread, BLOCKSIZE - bytesread, &bitstream);
#else
int bytes = ov_read(&vd->vf, vd->block + bytesread, BLOCKSIZE - bytesread, 0, 2, 1, &bitstream);
#endif
// fprintf(stderr, "ov_read = %d\n", bytes);
if (bytes > 0)
{
ogg_int64_t currentPosition;
bytesread += bytes;
if ((ogg_int64_t)(intptr_t)voice->LoopEnd > 0 &&
(currentPosition = ov_pcm_tell(&vd->vf)) >= (ogg_int64_t)(intptr_t)voice->LoopEnd)
{
bytesread -=
(currentPosition - (ogg_int64_t)(intptr_t)voice->LoopEnd) * voice->channels * 2; // (voice->bits>>3)
int const err = ov_pcm_seek(&vd->vf, (ogg_int64_t)(intptr_t)voice->LoopStart);
if (err != 0)
{
MV_Printf("MV_GetNextVorbisBlock ov_pcm_seek: LOOP_START %l, LOOP_END %l, err %d\n",
(ogg_int64_t)(intptr_t)voice->LoopStart, (ogg_int64_t)(intptr_t)voice->LoopEnd, err);
}
}
continue;
}
else if (bytes == OV_HOLE)
continue;
else if (bytes == 0)
{
if (voice->LoopSize > 0)
{
int const err = ov_pcm_seek(&vd->vf, (ogg_int64_t)(intptr_t)voice->LoopStart);
if (err != 0)
{
MV_Printf("MV_GetNextVorbisBlock ov_pcm_seek: LOOP_START %l, err %d\n",
(ogg_int64_t)(intptr_t)voice->LoopStart, err);
}
else
continue;
}
else
{
break;
}
}
else if (bytes < 0)
{
MV_Printf("MV_GetNextVorbisBlock ov_read: err %d\n", bytes);
return NoMoreData;
}
} while (bytesread < BLOCKSIZE);
if (bytesread == 0)
return NoMoreData;
if (bitstream != vd->lastbitstream)
{
vorbis_info *vi = ov_info(&vd->vf, -1);
if (!vi || (vi->channels != 1 && vi->channels != 2))
return NoMoreData;
voice->channels = vi->channels;
voice->SamplingRate = vi->rate;
voice->RateScale = divideu32(voice->SamplingRate * voice->PitchScale, MV_MixRate);
voice->FixedPointBufferSize = (voice->RateScale * MV_MIXBUFFERSIZE) - voice->RateScale;
vd->lastbitstream = bitstream;
MV_SetVoiceMixMode(voice);
}
uint32_t const samples = divideu32(bytesread, ((voice->bits>>3) * voice->channels));
voice->position = 0;
voice->sound = vd->block;
voice->BlockLength = 0;
voice->length = samples << 16;
#ifdef GEKKO
// If libtremor had the three additional ov_read() parameters that libvorbis has,
// this would be better handled using the endianness parameter.
int16_t *data = (int16_t *)(vd->block); // assumes signed 16-bit
for (bytesread = 0; bytesread < BLOCKSIZE / 2; ++bytesread)
data[bytesread] = (data[bytesread] & 0xff) << 8 | ((data[bytesread] & 0xff00) >> 8);
#endif
return KeepPlaying;
}
/*---------------------------------------------------------------------
Function: MV_PlayVorbis3D
Begin playback of sound data at specified angle and distance
from listener.
---------------------------------------------------------------------*/
int MV_PlayVorbis3D(char *ptr, uint32_t length, int loophow, int pitchoffset, int angle, int distance, int priority, float volume, intptr_t callbackval)
{
if (!MV_Installed)
return MV_SetErrorCode(MV_NotInstalled);
if (distance < 0)
{
distance = -distance;
angle += MV_NUMPANPOSITIONS / 2;
}
int const vol = MIX_VOLUME(distance);
// Ensure angle is within 0 - 127
angle &= MV_MAXPANPOSITION;
return MV_PlayVorbis(ptr, length, loophow, -1, pitchoffset, max(0, 255 - distance),
MV_PanTable[angle][vol].left, MV_PanTable[angle][vol].right, priority, volume, callbackval);
}
/*---------------------------------------------------------------------
Function: MV_PlayVorbis
Begin playback of sound data with the given sound levels and
priority.
---------------------------------------------------------------------*/
int MV_PlayVorbis(char *ptr, uint32_t length, int loopstart, int loopend, int pitchoffset, int vol, int left, int right, int priority, float volume, intptr_t callbackval)
{
UNREFERENCED_PARAMETER(loopend);
if (!MV_Installed)
return MV_SetErrorCode(MV_NotInstalled);
VoiceNode *voice = MV_AllocVoice(priority);
if (voice == nullptr)
return MV_SetErrorCode(MV_NoVoices);
auto vd = (vorbis_data *)Xcalloc(1, sizeof(vorbis_data));
vd->ptr = ptr;
vd->pos = 0;
vd->length = length;
vd->lastbitstream = -1;
int status = ov_open_callbacks((void *)vd, &vd->vf, 0, 0, vorbis_callbacks);
vorbis_info *vi;
if (status < 0 || ((vi = ov_info(&vd->vf, 0)) == nullptr) || vi->channels < 1 || vi->channels > 2)
{
if (status == 0)
ov_clear(&vd->vf);
else
MV_Printf("MV_PlayVorbis: err %d\n", status);
Xfree(vd);
return MV_SetErrorCode(MV_InvalidFile);
}
voice->wavetype = FMT_VORBIS;
voice->bits = 16;
voice->channels = vi->channels;
voice->rawdataptr = (void *)vd;
voice->GetSound = MV_GetNextVorbisBlock;
voice->NextBlock = vd->block;
voice->LoopCount = 0;
voice->BlockLength = 0;
voice->length = 0;
voice->next = nullptr;
voice->prev = nullptr;
voice->priority = priority;
voice->callbackval = callbackval;
voice->LoopStart = nullptr;
voice->LoopEnd = nullptr;
voice->LoopSize = (loopstart >= 0 ? 1 : 0);
// load loop tags from metadata
if (auto comment = ov_comment(&vd->vf, 0))
MV_GetVorbisCommentLoops(voice, comment);
voice->Paused = FALSE;
MV_SetVoicePitch(voice, vi->rate, pitchoffset);
MV_SetVoiceMixMode(voice);
MV_SetVoiceVolume(voice, vol, left, right, volume);
MV_PlayVoice(voice);
return voice->handle;
}
void MV_ReleaseVorbisVoice( VoiceNode * voice )
{
if (voice->wavetype != FMT_VORBIS)
return;
auto vd = (vorbis_data *)voice->rawdataptr;
voice->length = 0;
voice->sound = nullptr;
ov_clear(&vd->vf);
Xfree(vd);
}
#else
#include "_multivc.h"
int MV_PlayVorbis(char *ptr, uint32_t ptrlength, int loopstart, int loopend, int pitchoffset,
int vol, int left, int right, int priority, float volume, intptr_t callbackval)
{
UNREFERENCED_PARAMETER(ptr);
UNREFERENCED_PARAMETER(ptrlength);
UNREFERENCED_PARAMETER(loopstart);
UNREFERENCED_PARAMETER(loopend);
UNREFERENCED_PARAMETER(pitchoffset);
UNREFERENCED_PARAMETER(vol);
UNREFERENCED_PARAMETER(left);
UNREFERENCED_PARAMETER(right);
UNREFERENCED_PARAMETER(priority);
UNREFERENCED_PARAMETER(volume);
UNREFERENCED_PARAMETER(callbackval);
MV_Printf("MV_PlayVorbis: OggVorbis support not included in this binary.\n");
return -1;
}
int MV_PlayVorbis3D(char *ptr, uint32_t ptrlength, int loophow, int pitchoffset, int angle,
int distance, int priority, float volume, intptr_t callbackval)
{
UNREFERENCED_PARAMETER(ptr);
UNREFERENCED_PARAMETER(ptrlength);
UNREFERENCED_PARAMETER(loophow);
UNREFERENCED_PARAMETER(pitchoffset);
UNREFERENCED_PARAMETER(angle);
UNREFERENCED_PARAMETER(distance);
UNREFERENCED_PARAMETER(priority);
UNREFERENCED_PARAMETER(volume);
UNREFERENCED_PARAMETER(callbackval);
MV_Printf("MV_PlayVorbis: OggVorbis support not included in this binary.\n");
return -1;
}
#endif //HAVE_VORBIS

View file

@ -28,7 +28,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "common_game.h" #include "common_game.h"
#include "build.h" #include "build.h"
#include "sndcards.h"
#include "hash.h" #include "hash.h"
#include "renderlayer.h" #include "renderlayer.h"
#include "gamecontrol.h" #include "gamecontrol.h"

View file

@ -27,7 +27,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "osd.h" #include "osd.h"
#include "compat.h" #include "compat.h"
#include "mmulti.h" #include "mmulti.h"
#include "sndcards.h"
#include "common_game.h" #include "common_game.h"
#include "config.h" #include "config.h"
#include "blood.h" #include "blood.h"

View file

@ -30,7 +30,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "resource.h" #include "resource.h"
#include "sound.h" #include "sound.h"
#include "renderlayer.h" #include "renderlayer.h"
#include "al_midi.h"
#include "openaudio.h" #include "openaudio.h"
#include "z_music.h" #include "z_music.h"
#include "sfx.h" #include "sfx.h"