mirror of
https://github.com/DrBeef/Raze.git
synced 2024-11-22 20:21:20 +00:00
- be gone, MultiVoc.
This commit is contained in:
parent
2cf9a4a626
commit
a6395c0ed9
61 changed files with 2 additions and 18092 deletions
|
@ -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} )
|
||||||
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
@ -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
|
@ -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
|
|
|
@ -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 */
|
|
|
@ -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 */
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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.
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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__
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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++);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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);
|
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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__
|
|
|
@ -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, ¤tMidiBuffer->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, ¤tMidiBuffer->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, ¤tMidiBuffer->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:
|
|
|
@ -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);
|
|
||||||
|
|
|
@ -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:
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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 }
|
|
||||||
};
|
|
|
@ -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
|
@ -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
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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
|
@ -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);
|
|
||||||
}
|
|
|
@ -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
|
|
|
@ -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
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in a new issue