1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-15 11:03:00 +01:00

A new custom software mixer, supports playing streams at any rate, which is needed to emulate the directsound SetFrequency effects (when a ride malfunctions and the music slows down and stops). The speex resampler is added for this. Currently samples can be played and their volumes and looping set on an arbitrary number of channels. Support for FLAC and other streaming formats can be added.

This commit is contained in:
zsilencer
2014-09-05 19:29:22 -06:00
parent a284d446ee
commit bf805057f2
16 changed files with 2704 additions and 28 deletions

239
libspeex/arch.h Normal file
View File

@@ -0,0 +1,239 @@
/* Copyright (C) 2003 Jean-Marc Valin */
/**
@file arch.h
@brief Various architecture definitions Speex
*/
/*
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 ARCH_H
#define ARCH_H
#ifndef SPEEX_VERSION
#define SPEEX_MAJOR_VERSION 1 /**< Major Speex version. */
#define SPEEX_MINOR_VERSION 1 /**< Minor Speex version. */
#define SPEEX_MICRO_VERSION 15 /**< Micro Speex version. */
#define SPEEX_EXTRA_VERSION "" /**< Extra Speex version. */
#define SPEEX_VERSION "speex-1.2beta3" /**< Speex version string. */
#endif
/* A couple test to catch stupid option combinations */
#ifdef FIXED_POINT
#ifdef FLOATING_POINT
#error You cannot compile as floating point and fixed point at the same time
#endif
#ifdef _USE_SSE
#error SSE is only for floating-point
#endif
#if ((defined (ARM4_ASM)||defined (ARM4_ASM)) && defined(BFIN_ASM)) || (defined (ARM4_ASM)&&defined(ARM5E_ASM))
#error Make up your mind. What CPU do you have?
#endif
#ifdef VORBIS_PSYCHO
#error Vorbis-psy model currently not implemented in fixed-point
#endif
#else
#ifndef FLOATING_POINT
#error You now need to define either FIXED_POINT or FLOATING_POINT
#endif
#if defined (ARM4_ASM) || defined(ARM5E_ASM) || defined(BFIN_ASM)
#error I suppose you can have a [ARM4/ARM5E/Blackfin] that has float instructions?
#endif
#ifdef FIXED_POINT_DEBUG
#error "Don't you think enabling fixed-point is a good thing to do if you want to debug that?"
#endif
#endif
#ifndef OUTSIDE_SPEEX
#include "speex/speex_types.h"
#endif
#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */
#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */
#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 16-bit value. */
#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */
#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */
#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Maximum 32-bit value. */
#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */
#ifdef FIXED_POINT
typedef spx_int16_t spx_word16_t;
typedef spx_int32_t spx_word32_t;
typedef spx_word32_t spx_mem_t;
typedef spx_word16_t spx_coef_t;
typedef spx_word16_t spx_lsp_t;
typedef spx_word32_t spx_sig_t;
#define Q15ONE 32767
#define LPC_SCALING 8192
#define SIG_SCALING 16384
#define LSP_SCALING 8192.
#define GAMMA_SCALING 32768.
#define GAIN_SCALING 64
#define GAIN_SCALING_1 0.015625
#define LPC_SHIFT 13
#define LSP_SHIFT 13
#define SIG_SHIFT 14
#define GAIN_SHIFT 6
#define VERY_SMALL 0
#define VERY_LARGE32 ((spx_word32_t)2147483647)
#define VERY_LARGE16 ((spx_word16_t)32767)
#define Q15_ONE ((spx_word16_t)32767)
#ifdef FIXED_DEBUG
#include "fixed_debug.h"
#else
#include "fixed_generic.h"
#ifdef ARM5E_ASM
#include "fixed_arm5e.h"
#elif defined (ARM4_ASM)
#include "fixed_arm4.h"
#elif defined (BFIN_ASM)
#include "fixed_bfin.h"
#endif
#endif
#else
typedef float spx_mem_t;
typedef float spx_coef_t;
typedef float spx_lsp_t;
typedef float spx_sig_t;
typedef float spx_word16_t;
typedef float spx_word32_t;
#define Q15ONE 1.0f
#define LPC_SCALING 1.f
#define SIG_SCALING 1.f
#define LSP_SCALING 1.f
#define GAMMA_SCALING 1.f
#define GAIN_SCALING 1.f
#define GAIN_SCALING_1 1.f
#define VERY_SMALL 1e-15f
#define VERY_LARGE32 1e15f
#define VERY_LARGE16 1e15f
#define Q15_ONE ((spx_word16_t)1.f)
#define QCONST16(x,bits) (x)
#define QCONST32(x,bits) (x)
#define NEG16(x) (-(x))
#define NEG32(x) (-(x))
#define EXTRACT16(x) (x)
#define EXTEND32(x) (x)
#define SHR16(a,shift) (a)
#define SHL16(a,shift) (a)
#define SHR32(a,shift) (a)
#define SHL32(a,shift) (a)
#define PSHR16(a,shift) (a)
#define PSHR32(a,shift) (a)
#define VSHR32(a,shift) (a)
#define SATURATE16(x,a) (x)
#define SATURATE32(x,a) (x)
#define PSHR(a,shift) (a)
#define SHR(a,shift) (a)
#define SHL(a,shift) (a)
#define SATURATE(x,a) (x)
#define ADD16(a,b) ((a)+(b))
#define SUB16(a,b) ((a)-(b))
#define ADD32(a,b) ((a)+(b))
#define SUB32(a,b) ((a)-(b))
#define MULT16_16_16(a,b) ((a)*(b))
#define MULT16_16(a,b) ((spx_word32_t)(a)*(spx_word32_t)(b))
#define MAC16_16(c,a,b) ((c)+(spx_word32_t)(a)*(spx_word32_t)(b))
#define MULT16_32_Q11(a,b) ((a)*(b))
#define MULT16_32_Q13(a,b) ((a)*(b))
#define MULT16_32_Q14(a,b) ((a)*(b))
#define MULT16_32_Q15(a,b) ((a)*(b))
#define MULT16_32_P15(a,b) ((a)*(b))
#define MAC16_32_Q11(c,a,b) ((c)+(a)*(b))
#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b))
#define MAC16_16_Q11(c,a,b) ((c)+(a)*(b))
#define MAC16_16_Q13(c,a,b) ((c)+(a)*(b))
#define MAC16_16_P13(c,a,b) ((c)+(a)*(b))
#define MULT16_16_Q11_32(a,b) ((a)*(b))
#define MULT16_16_Q13(a,b) ((a)*(b))
#define MULT16_16_Q14(a,b) ((a)*(b))
#define MULT16_16_Q15(a,b) ((a)*(b))
#define MULT16_16_P15(a,b) ((a)*(b))
#define MULT16_16_P13(a,b) ((a)*(b))
#define MULT16_16_P14(a,b) ((a)*(b))
#define DIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b))
#define PDIV32_16(a,b) (((spx_word32_t)(a))/(spx_word16_t)(b))
#define DIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b))
#define PDIV32(a,b) (((spx_word32_t)(a))/(spx_word32_t)(b))
#endif
#if defined (CONFIG_TI_C54X) || defined (CONFIG_TI_C55X)
/* 2 on TI C5x DSP */
#define BYTES_PER_CHAR 2
#define BITS_PER_CHAR 16
#define LOG2_BITS_PER_CHAR 4
#else
#define BYTES_PER_CHAR 1
#define BITS_PER_CHAR 8
#define LOG2_BITS_PER_CHAR 3
#endif
#ifdef FIXED_DEBUG
extern long long spx_mips;
#endif
#endif

20
libspeex/config.h Normal file
View File

@@ -0,0 +1,20 @@
// Microsoft version of 'inline'
#define inline __inline
// Visual Studio support alloca(), but it always align variables to 16-bit
// boundary, while SSE need 128-bit alignment. So we disable alloca() when
// SSE is enabled.
#ifndef _USE_SSE
# define USE_ALLOCA
#endif
/* Default to floating point */
#ifndef FIXED_POINT
# define FLOATING_POINT
# define USE_SMALLFT
#else
# define USE_KISS_FFT
#endif
/* We don't support visibility on Win32 */
#define EXPORT

169
libspeex/os_support.h Normal file
View File

@@ -0,0 +1,169 @@
/* Copyright (C) 2007 Jean-Marc Valin
File: os_support.h
This is the (tiny) OS abstraction layer. Aside from math.h, this is the
only place where system headers are allowed.
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.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 OS_SUPPORT_H
#define OS_SUPPORT_H
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef OS_SUPPORT_CUSTOM
#include "os_support_custom.h"
#endif
/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_free
NOTE: speex_alloc needs to CLEAR THE MEMORY */
#ifndef OVERRIDE_SPEEX_ALLOC
static inline void *speex_alloc (int size)
{
/* WARNING: this is not equivalent to malloc(). If you want to use malloc()
or your own allocator, YOU NEED TO CLEAR THE MEMORY ALLOCATED. Otherwise
you will experience strange bugs */
return calloc(size,1);
}
#endif
/** Same as speex_alloc, except that the area is only needed inside a Speex call (might cause problem with wideband though) */
#ifndef OVERRIDE_SPEEX_ALLOC_SCRATCH
static inline void *speex_alloc_scratch (int size)
{
/* Scratch space doesn't need to be cleared */
return calloc(size,1);
}
#endif
/** Speex wrapper for realloc. To do your own dynamic allocation, all you need to do is replace this function, speex_alloc and speex_free */
#ifndef OVERRIDE_SPEEX_REALLOC
static inline void *speex_realloc (void *ptr, int size)
{
return realloc(ptr, size);
}
#endif
/** Speex wrapper for calloc. To do your own dynamic allocation, all you need to do is replace this function, speex_realloc and speex_alloc */
#ifndef OVERRIDE_SPEEX_FREE
static inline void speex_free (void *ptr)
{
free(ptr);
}
#endif
/** Same as speex_free, except that the area is only needed inside a Speex call (might cause problem with wideband though) */
#ifndef OVERRIDE_SPEEX_FREE_SCRATCH
static inline void speex_free_scratch (void *ptr)
{
free(ptr);
}
#endif
/** Copy n bytes of memory from src to dst. The 0* term provides compile-time type checking */
#ifndef OVERRIDE_SPEEX_COPY
#define SPEEX_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))
#endif
/** Copy n bytes of memory from src to dst, allowing overlapping regions. The 0* term
provides compile-time type checking */
#ifndef OVERRIDE_SPEEX_MOVE
#define SPEEX_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))
#endif
/** Set n bytes of memory to value of c, starting at address s */
#ifndef OVERRIDE_SPEEX_MEMSET
#define SPEEX_MEMSET(dst, c, n) (memset((dst), (c), (n)*sizeof(*(dst))))
#endif
#ifndef OVERRIDE_SPEEX_FATAL
static inline void _speex_fatal(const char *str, const char *file, int line)
{
fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str);
exit(1);
}
#endif
#ifndef OVERRIDE_SPEEX_WARNING
static inline void speex_warning(const char *str)
{
#ifndef DISABLE_WARNINGS
fprintf (stderr, "warning: %s\n", str);
#endif
}
#endif
#ifndef OVERRIDE_SPEEX_WARNING_INT
static inline void speex_warning_int(const char *str, int val)
{
#ifndef DISABLE_WARNINGS
fprintf (stderr, "warning: %s %d\n", str, val);
#endif
}
#endif
#ifndef OVERRIDE_SPEEX_NOTIFY
static inline void speex_notify(const char *str)
{
#ifndef DISABLE_NOTIFICATIONS
fprintf (stderr, "notification: %s\n", str);
#endif
}
#endif
#ifndef OVERRIDE_SPEEX_PUTC
/** Speex wrapper for putc */
static inline void _speex_putc(int ch, void *file)
{
FILE *f = (FILE *)file;
fprintf(f, "%c", ch);
}
#endif
#define speex_fatal(str) _speex_fatal(str, __FILE__, __LINE__);
#define speex_assert(cond) {if (!(cond)) {speex_fatal("assertion failed: " #cond);}}
#ifndef RELEASE
static inline void print_vec(float *vec, int len, char *name)
{
int i;
printf ("%s ", name);
for (i=0;i<len;i++)
printf (" %f", vec[i]);
printf ("\n");
}
#endif
#endif

1131
libspeex/resample.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,340 @@
/* Copyright (C) 2007 Jean-Marc Valin
File: speex_resampler.h
Resampling code
The design goals of this code are:
- Very fast algorithm
- Low memory requirement
- Good *perceptual* quality (and not best SNR)
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.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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 SPEEX_RESAMPLER_H
#define SPEEX_RESAMPLER_H
#ifdef OUTSIDE_SPEEX
/********* WARNING: MENTAL SANITY ENDS HERE *************/
/* If the resampler is defined outside of Speex, we change the symbol names so that
there won't be any clash if linking with Speex later on. */
/* #define RANDOM_PREFIX your software name here */
#ifndef RANDOM_PREFIX
#error "Please define RANDOM_PREFIX (above) to something specific to your project to prevent symbol name clashes"
#endif
#define CAT_PREFIX2(a,b) a ## b
#define CAT_PREFIX(a,b) CAT_PREFIX2(a, b)
#define speex_resampler_init CAT_PREFIX(RANDOM_PREFIX,_resampler_init)
#define speex_resampler_init_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_init_frac)
#define speex_resampler_destroy CAT_PREFIX(RANDOM_PREFIX,_resampler_destroy)
#define speex_resampler_process_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_float)
#define speex_resampler_process_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_int)
#define speex_resampler_process_interleaved_float CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_float)
#define speex_resampler_process_interleaved_int CAT_PREFIX(RANDOM_PREFIX,_resampler_process_interleaved_int)
#define speex_resampler_set_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate)
#define speex_resampler_get_rate CAT_PREFIX(RANDOM_PREFIX,_resampler_get_rate)
#define speex_resampler_set_rate_frac CAT_PREFIX(RANDOM_PREFIX,_resampler_set_rate_frac)
#define speex_resampler_get_ratio CAT_PREFIX(RANDOM_PREFIX,_resampler_get_ratio)
#define speex_resampler_set_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_set_quality)
#define speex_resampler_get_quality CAT_PREFIX(RANDOM_PREFIX,_resampler_get_quality)
#define speex_resampler_set_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_input_stride)
#define speex_resampler_get_input_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_stride)
#define speex_resampler_set_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_set_output_stride)
#define speex_resampler_get_output_stride CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_stride)
#define speex_resampler_get_input_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_input_latency)
#define speex_resampler_get_output_latency CAT_PREFIX(RANDOM_PREFIX,_resampler_get_output_latency)
#define speex_resampler_skip_zeros CAT_PREFIX(RANDOM_PREFIX,_resampler_skip_zeros)
#define speex_resampler_reset_mem CAT_PREFIX(RANDOM_PREFIX,_resampler_reset_mem)
#define speex_resampler_strerror CAT_PREFIX(RANDOM_PREFIX,_resampler_strerror)
#define spx_int16_t short
#define spx_int32_t int
#define spx_uint16_t unsigned short
#define spx_uint32_t unsigned int
#else /* OUTSIDE_SPEEX */
#include "speex/speex_types.h"
#endif /* OUTSIDE_SPEEX */
#ifdef __cplusplus
extern "C" {
#endif
#define SPEEX_RESAMPLER_QUALITY_MAX 10
#define SPEEX_RESAMPLER_QUALITY_MIN 0
#define SPEEX_RESAMPLER_QUALITY_DEFAULT 4
#define SPEEX_RESAMPLER_QUALITY_VOIP 3
#define SPEEX_RESAMPLER_QUALITY_DESKTOP 5
enum {
RESAMPLER_ERR_SUCCESS = 0,
RESAMPLER_ERR_ALLOC_FAILED = 1,
RESAMPLER_ERR_BAD_STATE = 2,
RESAMPLER_ERR_INVALID_ARG = 3,
RESAMPLER_ERR_PTR_OVERLAP = 4,
RESAMPLER_ERR_MAX_ERROR
};
struct SpeexResamplerState_;
typedef struct SpeexResamplerState_ SpeexResamplerState;
/** Create a new resampler with integer input and output rates.
* @param nb_channels Number of channels to be processed
* @param in_rate Input sampling rate (integer number of Hz).
* @param out_rate Output sampling rate (integer number of Hz).
* @param quality Resampling quality between 0 and 10, where 0 has poor quality
* and 10 has very high quality.
* @return Newly created resampler state
* @retval NULL Error: not enough memory
*/
SpeexResamplerState *speex_resampler_init(spx_uint32_t nb_channels,
spx_uint32_t in_rate,
spx_uint32_t out_rate,
int quality,
int *err);
/** Create a new resampler with fractional input/output rates. The sampling
* rate ratio is an arbitrary rational number with both the numerator and
* denominator being 32-bit integers.
* @param nb_channels Number of channels to be processed
* @param ratio_num Numerator of the sampling rate ratio
* @param ratio_den Denominator of the sampling rate ratio
* @param in_rate Input sampling rate rounded to the nearest integer (in Hz).
* @param out_rate Output sampling rate rounded to the nearest integer (in Hz).
* @param quality Resampling quality between 0 and 10, where 0 has poor quality
* and 10 has very high quality.
* @return Newly created resampler state
* @retval NULL Error: not enough memory
*/
SpeexResamplerState *speex_resampler_init_frac(spx_uint32_t nb_channels,
spx_uint32_t ratio_num,
spx_uint32_t ratio_den,
spx_uint32_t in_rate,
spx_uint32_t out_rate,
int quality,
int *err);
/** Destroy a resampler state.
* @param st Resampler state
*/
void speex_resampler_destroy(SpeexResamplerState *st);
/** Resample a float array. The input and output buffers must *not* overlap.
* @param st Resampler state
* @param channel_index Index of the channel to process for the multi-channel
* base (0 otherwise)
* @param in Input buffer
* @param in_len Number of input samples in the input buffer. Returns the
* number of samples processed
* @param out Output buffer
* @param out_len Size of the output buffer. Returns the number of samples written
*/
int speex_resampler_process_float(SpeexResamplerState *st,
spx_uint32_t channel_index,
const float *in,
spx_uint32_t *in_len,
float *out,
spx_uint32_t *out_len);
/** Resample an int array. The input and output buffers must *not* overlap.
* @param st Resampler state
* @param channel_index Index of the channel to process for the multi-channel
* base (0 otherwise)
* @param in Input buffer
* @param in_len Number of input samples in the input buffer. Returns the number
* of samples processed
* @param out Output buffer
* @param out_len Size of the output buffer. Returns the number of samples written
*/
int speex_resampler_process_int(SpeexResamplerState *st,
spx_uint32_t channel_index,
const spx_int16_t *in,
spx_uint32_t *in_len,
spx_int16_t *out,
spx_uint32_t *out_len);
/** Resample an interleaved float array. The input and output buffers must *not* overlap.
* @param st Resampler state
* @param in Input buffer
* @param in_len Number of input samples in the input buffer. Returns the number
* of samples processed. This is all per-channel.
* @param out Output buffer
* @param out_len Size of the output buffer. Returns the number of samples written.
* This is all per-channel.
*/
int speex_resampler_process_interleaved_float(SpeexResamplerState *st,
const float *in,
spx_uint32_t *in_len,
float *out,
spx_uint32_t *out_len);
/** Resample an interleaved int array. The input and output buffers must *not* overlap.
* @param st Resampler state
* @param in Input buffer
* @param in_len Number of input samples in the input buffer. Returns the number
* of samples processed. This is all per-channel.
* @param out Output buffer
* @param out_len Size of the output buffer. Returns the number of samples written.
* This is all per-channel.
*/
int speex_resampler_process_interleaved_int(SpeexResamplerState *st,
const spx_int16_t *in,
spx_uint32_t *in_len,
spx_int16_t *out,
spx_uint32_t *out_len);
/** Set (change) the input/output sampling rates (integer value).
* @param st Resampler state
* @param in_rate Input sampling rate (integer number of Hz).
* @param out_rate Output sampling rate (integer number of Hz).
*/
int speex_resampler_set_rate(SpeexResamplerState *st,
spx_uint32_t in_rate,
spx_uint32_t out_rate);
/** Get the current input/output sampling rates (integer value).
* @param st Resampler state
* @param in_rate Input sampling rate (integer number of Hz) copied.
* @param out_rate Output sampling rate (integer number of Hz) copied.
*/
void speex_resampler_get_rate(SpeexResamplerState *st,
spx_uint32_t *in_rate,
spx_uint32_t *out_rate);
/** Set (change) the input/output sampling rates and resampling ratio
* (fractional values in Hz supported).
* @param st Resampler state
* @param ratio_num Numerator of the sampling rate ratio
* @param ratio_den Denominator of the sampling rate ratio
* @param in_rate Input sampling rate rounded to the nearest integer (in Hz).
* @param out_rate Output sampling rate rounded to the nearest integer (in Hz).
*/
int speex_resampler_set_rate_frac(SpeexResamplerState *st,
spx_uint32_t ratio_num,
spx_uint32_t ratio_den,
spx_uint32_t in_rate,
spx_uint32_t out_rate);
/** Get the current resampling ratio. This will be reduced to the least
* common denominator.
* @param st Resampler state
* @param ratio_num Numerator of the sampling rate ratio copied
* @param ratio_den Denominator of the sampling rate ratio copied
*/
void speex_resampler_get_ratio(SpeexResamplerState *st,
spx_uint32_t *ratio_num,
spx_uint32_t *ratio_den);
/** Set (change) the conversion quality.
* @param st Resampler state
* @param quality Resampling quality between 0 and 10, where 0 has poor
* quality and 10 has very high quality.
*/
int speex_resampler_set_quality(SpeexResamplerState *st,
int quality);
/** Get the conversion quality.
* @param st Resampler state
* @param quality Resampling quality between 0 and 10, where 0 has poor
* quality and 10 has very high quality.
*/
void speex_resampler_get_quality(SpeexResamplerState *st,
int *quality);
/** Set (change) the input stride.
* @param st Resampler state
* @param stride Input stride
*/
void speex_resampler_set_input_stride(SpeexResamplerState *st,
spx_uint32_t stride);
/** Get the input stride.
* @param st Resampler state
* @param stride Input stride copied
*/
void speex_resampler_get_input_stride(SpeexResamplerState *st,
spx_uint32_t *stride);
/** Set (change) the output stride.
* @param st Resampler state
* @param stride Output stride
*/
void speex_resampler_set_output_stride(SpeexResamplerState *st,
spx_uint32_t stride);
/** Get the output stride.
* @param st Resampler state copied
* @param stride Output stride
*/
void speex_resampler_get_output_stride(SpeexResamplerState *st,
spx_uint32_t *stride);
/** Get the latency in input samples introduced by the resampler.
* @param st Resampler state
*/
int speex_resampler_get_input_latency(SpeexResamplerState *st);
/** Get the latency in output samples introduced by the resampler.
* @param st Resampler state
*/
int speex_resampler_get_output_latency(SpeexResamplerState *st);
/** Make sure that the first samples to go out of the resamplers don't have
* leading zeros. This is only useful before starting to use a newly created
* resampler. It is recommended to use that when resampling an audio file, as
* it will generate a file with the same length. For real-time processing,
* it is probably easier not to use this call (so that the output duration
* is the same for the first frame).
* @param st Resampler state
*/
int speex_resampler_skip_zeros(SpeexResamplerState *st);
/** Reset a resampler so a new (unrelated) stream can be processed.
* @param st Resampler state
*/
int speex_resampler_reset_mem(SpeexResamplerState *st);
/** Returns the English meaning for an error code
* @param err Error code
* @return English string
*/
const char *speex_resampler_strerror(int err);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,126 @@
/* speex_types.h taken from libogg */
/********************************************************************
* *
* 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 7524 2004-08-11 04:20:36Z conrad $
********************************************************************/
/**
@file speex_types.h
@brief Speex types
*/
#ifndef _SPEEX_TYPES_H
#define _SPEEX_TYPES_H
#if defined(_WIN32)
# if defined(__CYGWIN__)
# include <_G_config.h>
typedef _G_int32_t spx_int32_t;
typedef _G_uint32_t spx_uint32_t;
typedef _G_int16_t spx_int16_t;
typedef _G_uint16_t spx_uint16_t;
# elif defined(__MINGW32__)
typedef short spx_int16_t;
typedef unsigned short spx_uint16_t;
typedef int spx_int32_t;
typedef unsigned int spx_uint32_t;
# elif defined(__MWERKS__)
typedef int spx_int32_t;
typedef unsigned int spx_uint32_t;
typedef short spx_int16_t;
typedef unsigned short spx_uint16_t;
# else
/* MSVC/Borland */
typedef __int32 spx_int32_t;
typedef unsigned __int32 spx_uint32_t;
typedef __int16 spx_int16_t;
typedef unsigned __int16 spx_uint16_t;
# endif
#elif defined(__MACOS__)
# include <sys/types.h>
typedef SInt16 spx_int16_t;
typedef UInt16 spx_uint16_t;
typedef SInt32 spx_int32_t;
typedef UInt32 spx_uint32_t;
#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
# include <sys/types.h>
typedef int16_t spx_int16_t;
typedef u_int16_t spx_uint16_t;
typedef int32_t spx_int32_t;
typedef u_int32_t spx_uint32_t;
#elif defined(__BEOS__)
/* Be */
# include <inttypes.h>
typedef int16_t spx_int16_t;
typedef u_int16_t spx_uint16_t;
typedef int32_t spx_int32_t;
typedef u_int32_t spx_uint32_t;
#elif defined (__EMX__)
/* OS/2 GCC */
typedef short spx_int16_t;
typedef unsigned short spx_uint16_t;
typedef int spx_int32_t;
typedef unsigned int spx_uint32_t;
#elif defined (DJGPP)
/* DJGPP */
typedef short spx_int16_t;
typedef int spx_int32_t;
typedef unsigned int spx_uint32_t;
#elif defined(R5900)
/* PS2 EE */
typedef int spx_int32_t;
typedef unsigned spx_uint32_t;
typedef short spx_int16_t;
#elif defined(__SYMBIAN32__)
/* Symbian GCC */
typedef signed short spx_int16_t;
typedef unsigned short spx_uint16_t;
typedef signed int spx_int32_t;
typedef unsigned int spx_uint32_t;
#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X)
typedef short spx_int16_t;
typedef unsigned short spx_uint16_t;
typedef long spx_int32_t;
typedef unsigned long spx_uint32_t;
#elif defined(CONFIG_TI_C6X)
typedef short spx_int16_t;
typedef unsigned short spx_uint16_t;
typedef int spx_int32_t;
typedef unsigned int spx_uint32_t;
#else
# include <speex/speex_config_types.h>
#endif
#endif /* _SPEEX_TYPES_H */

115
libspeex/stack_alloc.h Normal file
View File

@@ -0,0 +1,115 @@
/* Copyright (C) 2002 Jean-Marc Valin */
/**
@file stack_alloc.h
@brief Temporary memory allocation on stack
*/
/*
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 STACK_ALLOC_H
#define STACK_ALLOC_H
#ifdef USE_ALLOCA
# ifdef WIN32
# include <malloc.h>
# else
# ifdef HAVE_ALLOCA_H
# include <alloca.h>
# else
# include <stdlib.h>
# endif
# endif
#endif
/**
* @def ALIGN(stack, size)
*
* Aligns the stack to a 'size' boundary
*
* @param stack Stack
* @param size New size boundary
*/
/**
* @def PUSH(stack, size, type)
*
* Allocates 'size' elements of type 'type' on the stack
*
* @param stack Stack
* @param size Number of elements
* @param type Type of element
*/
/**
* @def VARDECL(var)
*
* Declare variable on stack
*
* @param var Variable to declare
*/
/**
* @def ALLOC(var, size, type)
*
* Allocate 'size' elements of 'type' on stack
*
* @param var Name of variable to allocate
* @param size Number of elements
* @param type Type of element
*/
#ifdef ENABLE_VALGRIND
#include <valgrind/memcheck.h>
#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
#define PUSH(stack, size, type) (VALGRIND_MAKE_NOACCESS(stack, 1000),ALIGN((stack),sizeof(type)),VALGRIND_MAKE_WRITABLE(stack, ((size)*sizeof(type))),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type))))
#else
#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)),(stack)+=((size)*sizeof(type)),(type*)((stack)-((size)*sizeof(type))))
#endif
#if defined(VAR_ARRAYS)
#define VARDECL(var)
#define ALLOC(var, size, type) type var[size]
#elif defined(USE_ALLOCA)
#define VARDECL(var) var
#define ALLOC(var, size, type) var = _alloca(sizeof(type)*(size))
#else
#define VARDECL(var) var
#define ALLOC(var, size, type) var = PUSH(stack, size, type)
#endif
#endif

View File

@@ -33,6 +33,7 @@
<ClInclude Include="..\src\language.h" />
<ClInclude Include="..\src\map.h" />
<ClInclude Include="..\src\marketing.h" />
<ClInclude Include="..\src\mixer.h" />
<ClInclude Include="..\src\news_item.h" />
<ClInclude Include="..\src\object.h" />
<ClInclude Include="..\src\osinterface.h" />
@@ -63,6 +64,7 @@
<ClInclude Include="..\src\staff.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\libspeex\resample.c" />
<ClCompile Include="..\lodepng\lodepng.c" />
<ClCompile Include="..\src\audio.c" />
<ClCompile Include="..\src\award.c" />
@@ -80,6 +82,7 @@
<ClCompile Include="..\src\language.c" />
<ClCompile Include="..\src\map.c" />
<ClCompile Include="..\src\marketing.c" />
<ClCompile Include="..\src\mixer.cpp" />
<ClCompile Include="..\src\news_item.c" />
<ClCompile Include="..\src\object.c" />
<ClCompile Include="..\src\object_list.c" />
@@ -186,7 +189,7 @@
<IntDir>$(SolutionDir)..\obj\$(Configuration)\</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<IncludePath>$(SolutionDir)..\lodepng;$(SolutionDir)..\sdl\include;$(IncludePath)</IncludePath>
<IncludePath>$(SolutionDir)..\lodepng;$(SolutionDir)..\sdl\include;$(SolutionDir)..\libspeex;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)..\sdl\lib\x86;$(LibraryPath)</LibraryPath>
<OutDir>$(SolutionDir)..\build\$(Configuration)\</OutDir>
<IntDir>$(SolutionDir)..\obj\$(Configuration)\</IntDir>
@@ -197,7 +200,7 @@
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<StructMemberAlignment>1Byte</StructMemberAlignment>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
@@ -218,7 +221,7 @@
<OmitFramePointers>
</OmitFramePointers>
<BufferSecurityCheck>false</BufferSecurityCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;HAVE_CONFIG_H;_USE_MATH_DEFINES;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ClCompile>
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>

View File

@@ -162,6 +162,9 @@
<ClInclude Include="..\src\input.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\src\mixer.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\src\game.c">
@@ -386,6 +389,12 @@
<ClCompile Include="..\src\window_ride.c">
<Filter>Windows</Filter>
</ClCompile>
<ClCompile Include="..\src\mixer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\libspeex\resample.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="..\openrct2.exe">

View File

@@ -215,14 +215,14 @@ int dsound_create_primary_buffer(int a, int device, int channels, int samples, i
}
dsdevice = &RCT2_GLOBAL(RCT2_ADDRESS_DSOUND_DEVICES, rct_dsdevice*)[device];
}
memset(&RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, rct_audio_info), 0, sizeof(rct_audio_info));
RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, rct_audio_info).var_0 = 1;
RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, rct_audio_info).channels = channels;
RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, rct_audio_info).samples = samples;
RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, rct_audio_info).var_8 = samples * RCT2_GLOBAL(0x01425B4C, uint16);
RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, rct_audio_info).bytes = bits * channels / 8;
RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, rct_audio_info).bits = bits;
RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, rct_audio_info).var_E = 0;
memset(&RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX), 0, sizeof(WAVEFORMATEX));
RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).wFormatTag = 1;
RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).nChannels = channels;
RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).nSamplesPerSec = samples;
RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).nAvgBytesPerSec = samples * RCT2_GLOBAL(0x01425B4C, uint16);
RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).nBlockAlign = bits * channels / 8;
RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).wBitsPerSample = bits;
RCT2_GLOBAL(RCT2_ADDRESS_AUDIO_INFO, WAVEFORMATEX).cbSize = 0;
DSBUFFERDESC bufferdesc;
memset(&bufferdesc, 0, sizeof(bufferdesc));
bufferdesc.dwSize = sizeof(bufferdesc);
@@ -466,8 +466,8 @@ int sub_4015E7(int channel)
} else {
sound_channel->var_168 = 1;
sound_channel->var_15C = read;
rct_audio_info* audio_info = sound_channel->hmem;
uint16 v = ((audio_info->var_E != 8) - 1) & 0x80;
LPWAVEFORMATEX waveformat = sound_channel->hmem;
uint16 v = ((waveformat->nBlockAlign != 8) - 1) & 0x80;
memset(&buf1[read], v, buf1size - r);
}
}
@@ -531,7 +531,7 @@ MMRESULT mmio_open(char* filename, HMMIO* hmmio, HGLOBAL* hmem, LPMMCKINFO mmcki
HMMIO hmmio1;
MMRESULT result;
MMCKINFO mmckinfo1;
rct_audio_info audio_info;
WAVEFORMATEX waveformat;
hmemold = hmem;
*hmem = 0;
@@ -555,8 +555,8 @@ MMRESULT mmio_open(char* filename, HMMIO* hmmio, HGLOBAL* hmem, LPMMCKINFO mmcki
result = 57601;
goto label20;
}
if (mmioRead(hmmio1, (HPSTR)&audio_info, 16) == 16) {
if (audio_info.var_0 == 1) {
if (mmioRead(hmmio1, (HPSTR)&waveformat, 16) == 16) {
if (waveformat.wFormatTag == 1) {
//strcpy(audio_info.var_0, "\x01");
hmem = 0;
label11:
@@ -566,7 +566,7 @@ MMRESULT mmio_open(char* filename, HMMIO* hmmio, HGLOBAL* hmem, LPMMCKINFO mmcki
result = 57344;
goto label20;
}
memcpy(hmemold2, &audio_info, 16);
memcpy(hmemold2, &waveformat, 16);
*((uint16*)*hmemold + 8) = (uint16)hmem;
if (!(uint16)hmem || mmioRead(hmmio1, (char*)*hmemold + 18, (uint16)hmem) == (uint16)hmem) {
result = mmioAscend(hmmio1, &mmckinfo1, 0);

View File

@@ -59,16 +59,6 @@ typedef struct rct_sound {
struct rct_sound* next;
} rct_sound;
typedef struct {
uint16 var_0;
uint16 channels;
uint32 samples;
uint32 var_8;
uint16 bytes;
uint16 bits;
uint16 var_E;
} rct_audio_info;
typedef struct {
uint32 var_0;
uint32 var_4;

401
src/mixer.cpp Normal file
View File

@@ -0,0 +1,401 @@
/*****************************************************************************
* Copyright (c) 2014 Ted John
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* This file is part of OpenRCT2.
*
* OpenRCT2 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 3 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, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#include <math.h>
#include <SDL.h>
#include <string.h>
extern "C" {
#include "audio.h"
#include "config.h"
}
#include "mixer.h"
Sample::Sample()
{
data = 0;
length = 0;
issdlwav = false;
}
Sample::~Sample()
{
Unload();
}
bool Sample::Load(char* filename)
{
Unload();
SDL_RWops* rw = SDL_RWFromFile(filename, "rb");
if (!rw) {
SDL_RWclose(rw);
return false;
}
SDL_AudioSpec audiospec;
memset(&audiospec, 0, sizeof(audiospec));
SDL_AudioSpec* spec = SDL_LoadWAV_RW(rw, false, &audiospec, &data, &length);
if (spec != NULL) {
format.freq = spec->freq;
format.format = spec->format;
format.channels = spec->channels;
} else {
issdlwav = true;
}
return true;
}
bool Sample::LoadCSS1(char* filename, unsigned int offset)
{
Unload();
SDL_RWops* rw = SDL_RWFromFile(filename, "rb");
if (!rw) {
return false;
}
Uint32 numsounds;
SDL_RWread(rw, &numsounds, sizeof(numsounds), 1);
if (offset > numsounds) {
SDL_RWclose(rw);
return false;
}
SDL_RWseek(rw, offset * 4, RW_SEEK_CUR);
Uint32 soundoffset;
SDL_RWread(rw, &soundoffset, sizeof(soundoffset), 1);
SDL_RWseek(rw, soundoffset, RW_SEEK_SET);
Uint32 soundsize;
SDL_RWread(rw, &soundsize, sizeof(soundsize), 1);
length = soundsize;
WAVEFORMATEX waveformat;
SDL_RWread(rw, &waveformat, sizeof(waveformat), 1);
format.freq = waveformat.nSamplesPerSec;
format.format = AUDIO_S16;
format.channels = (Uint8)waveformat.nChannels;
data = new Uint8[length];
SDL_RWread(rw, data, length, 1);
SDL_RWclose(rw);
return true;
}
void Sample::Unload()
{
SDL_LockAudio();
if (data) {
if (issdlwav) {
SDL_FreeWAV(data);
} else {
delete[] data;
}
data = 0;
}
issdlwav = false;
length = 0;
SDL_UnlockAudio();
}
bool Sample::Convert(AudioFormat format)
{
if(Sample::format.format != format.format || Sample::format.channels != format.channels || Sample::format.freq != format.freq){
SDL_AudioCVT cvt;
if (SDL_BuildAudioCVT(&cvt, Sample::format.format, Sample::format.channels, Sample::format.freq, format.format, format.channels, format.freq) < 0) {
return false;
}
cvt.len = length;
cvt.buf = new Uint8[cvt.len * cvt.len_mult];
memcpy(cvt.buf, data, length);
if (SDL_ConvertAudio(&cvt) < 0) {
delete[] cvt.buf;
return false;
}
Unload();
data = cvt.buf;
length = cvt.len_cvt;
Sample::format = format;
}
return true;
}
const Uint8* Sample::Data()
{
return data;
}
int Sample::Length()
{
return length;
}
Stream::Stream()
{
sourcetype = SOURCE_NONE;
}
int Stream::GetSome(int offset, const Uint8** data, int length)
{
int size = length;
switch(sourcetype) {
case SOURCE_SAMPLE:
if (offset >= sample->Length()) {
return 0;
}
if (offset + length > sample->Length()) {
size = sample->Length() - offset;
}
*data = &sample->Data()[offset];
return size;
break;
}
return 0;
}
int Stream::Length()
{
switch(sourcetype) {
case SOURCE_SAMPLE:
return sample->Length();
break;
}
return 0;
}
void Stream::SetSource_Sample(Sample& sample)
{
sourcetype = SOURCE_SAMPLE;
Stream::sample = &sample;
}
const AudioFormat* Stream::Format()
{
switch(sourcetype) {
case SOURCE_SAMPLE:
return &sample->format;
break;
}
return 0;
}
Channel::Channel()
{
rate = 1;
resampler = 0;
SetVolume(SDL_MIX_MAXVOLUME);
}
Channel::~Channel()
{
if (resampler) {
speex_resampler_destroy(resampler);
resampler = 0;
}
}
void Channel::Play(Stream& stream, int loop = 0)
{
Channel::stream = &stream;
Channel::loop = loop;
offset = 0;
}
void Channel::SetRate(double rate)
{
Channel::rate = rate;
if (Channel::rate < 0.001) {
Channel::rate = 0.001;
}
}
void Channel::SetVolume(int volume)
{
Channel::volume = volume;
if (Channel::volume > SDL_MIX_MAXVOLUME) {
Channel::volume = SDL_MIX_MAXVOLUME;
}
if (Channel::volume < 0) {
Channel::volume = 0;
}
}
void Mixer::Init(char* device)
{
Close();
SDL_AudioSpec want, have;
SDL_zero(want);
want.freq = 22050;
want.format = AUDIO_S16;
want.channels = 2;
want.samples = 1024;
want.callback = Callback;
want.userdata = this;
deviceid = SDL_OpenAudioDevice(device, 0, &want, &have, 0);
format.format = have.format;
format.channels = have.channels;
format.freq = have.freq;
char css1filename[260];
strcpy(css1filename, gGeneral_config.game_path);
strcat(css1filename, "\\Data\\css1.dat");
for (int i = 0; i < 63; i++) {
css1samples[i].LoadCSS1(css1filename, i);
css1samples[i].Convert(format); // convert to audio output format, saves some cpu usage but requires a bit more memory, optional
css1streams[i].SetSource_Sample(css1samples[i]);
}
SDL_PauseAudioDevice(deviceid, 0);
}
void Mixer::Close()
{
SDL_CloseAudioDevice(deviceid);
}
void SDLCALL Mixer::Callback(void* arg, Uint8* stream, int length)
{
Mixer* mixer = (Mixer*)arg;
memset(stream, 0, length);
for (int i = 0; i < 10; i++) {
mixer->MixChannel(mixer->channels[i], stream, length);
}
}
void Mixer::MixChannel(Channel& channel, Uint8* data, int length)
{
if (channel.stream) {
if (!channel.resampler) {
channel.resampler = speex_resampler_init(format.channels, format.freq, format.freq, 0, 0);
}
AudioFormat channelformat = *channel.stream->Format();
int loaded = 0;
SDL_AudioCVT cvt;
cvt.len_ratio = 1;
do {
int samplesize = format.channels * format.BytesPerSample();
int samples = length / samplesize;
int samplesloaded = loaded / samplesize;
int samplestoread = (int)ceil((samples - samplesloaded) * channel.rate);
int lengthloaded = 0;
if (channel.offset < channel.stream->Length()) {
bool mustconvert = false;
if (MustConvert(*channel.stream)) {
if (SDL_BuildAudioCVT(&cvt, channelformat.format, channelformat.channels, channelformat.freq, Mixer::format.format, Mixer::format.channels, Mixer::format.freq) == -1) {
break;
}
mustconvert = true;
}
const Uint8* datastream;
int readfromstream = (channel.stream->GetSome(channel.offset, &datastream, (int)(((samplestoread) * samplesize) / cvt.len_ratio)) / channelformat.BytesPerSample()) * channelformat.BytesPerSample();
if (readfromstream == 0) {
break;
}
int volume = channel.volume;
if (mustconvert) {
Uint8* dataconverted;
if (Convert(cvt, datastream, readfromstream, &dataconverted)) {
if (channel.rate != 1 && format.format == AUDIO_S16) {
spx_uint32_t in_len = (spx_uint32_t)(ceil((double)cvt.len_cvt / samplesize));
Uint8* out = new Uint8[length + 200]; // needs some extra, otherwise resampler sometimes doesn't process all the input samples
spx_uint32_t out_len = samples + 20;
speex_resampler_set_rate(channel.resampler, format.freq, (int)(format.freq * (1 / channel.rate)));
speex_resampler_process_interleaved_int(channel.resampler, (const spx_int16_t*)dataconverted, &in_len, (spx_int16_t*)out, &out_len);
int mixlength = (out_len * samplesize);
if (loaded + mixlength > length) { // check for overflow
mixlength = length - loaded;
}
lengthloaded = (out_len * samplesize);
SDL_MixAudioFormat(&data[loaded], out, format.format, mixlength, volume);
delete[] out;
} else {
lengthloaded = (cvt.len_cvt / samplesize) * samplesize;
int mixlength = lengthloaded;
if (loaded + cvt.len_cvt > length) {
mixlength = length - loaded;
}
SDL_MixAudioFormat(&data[loaded], dataconverted, format.format, mixlength, volume);
}
delete[] dataconverted;
}
} else {
if (channel.rate != 1 && format.format == AUDIO_S16) {
spx_uint32_t in_len = (spx_uint32_t)(ceil((double)readfromstream / samplesize));
Uint8* out = new Uint8[length + 200];
spx_uint32_t out_len = samples + 20;
speex_resampler_set_rate(channel.resampler, format.freq, (int)(format.freq * (1 / channel.rate)));
speex_resampler_process_interleaved_int(channel.resampler, (const spx_int16_t*)datastream, &in_len, (spx_int16_t*)out, &out_len);
int mixlength = (out_len * samplesize);
if (loaded + mixlength > length) {
mixlength = length - loaded;
}
lengthloaded = (out_len * samplesize);
SDL_MixAudioFormat(&data[loaded], out, format.format, mixlength, volume);
delete[] out;
} else {
lengthloaded = readfromstream;
int mixlength = lengthloaded;
if (loaded + readfromstream > length) {
mixlength = length - loaded;
}
SDL_MixAudioFormat(&data[loaded], datastream, format.format, mixlength, volume);
}
}
channel.offset += readfromstream;
}
loaded += lengthloaded;
if (channel.loop != 0 && channel.offset >= channel.stream->Length()) {
if (channel.loop != -1) {
channel.loop--;
}
channel.offset = 0;
}
} while(loaded < length || (loaded < length && channel.loop != 0 && channel.offset == 0));
}
}
bool Mixer::MustConvert(Stream& stream)
{
const AudioFormat* streamformat = stream.Format();
if (!streamformat) {
return false;
}
if (streamformat->format != format.format || streamformat->channels != format.channels || streamformat->freq != format.freq) {
return true;
}
return false;
}
bool Mixer::Convert(SDL_AudioCVT& cvt, const Uint8* data, int length, Uint8** dataout)
{
if (length == 0 || cvt.len_mult == 0) {
return false;
}
cvt.len = length;
cvt.buf = (Uint8*)new char[cvt.len * cvt.len_mult];
memcpy(cvt.buf, data, length);
if (SDL_ConvertAudio(&cvt) < 0) {
delete[] cvt.buf;
return false;
}
*dataout = cvt.buf;
return true;
}
void Mixer_Init(char* device)
{
static Mixer mixer;
mixer.Init(device);
}

127
src/mixer.h Normal file
View File

@@ -0,0 +1,127 @@
/*****************************************************************************
* Copyright (c) 2014 Ted John
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* This file is part of OpenRCT2.
*
* OpenRCT2 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 3 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, see <http://www.gnu.org/licenses/>.
*****************************************************************************/
#ifndef _MIXER_H_
#define _MIXER_H_
#include "rct2.h"
#ifdef __cplusplus
extern "C" {
#include <speex/speex_resampler.h>
}
struct AudioFormat {
int BytesPerSample() const { return (SDL_AUDIO_BITSIZE(format)) / 8; };
int freq;
SDL_AudioFormat format;
Uint8 channels;
};
class Sample
{
public:
Sample();
~Sample();
bool Load(char* filename);
bool LoadCSS1(char* filename, unsigned int offset);
void Unload();
bool Convert(AudioFormat format);
const Uint8* Data();
int Length();
friend class Stream;
private:
AudioFormat format;
Uint8* data;
Uint32 length;
bool issdlwav;
};
class Stream
{
public:
Stream();
int GetSome(int offset, const Uint8** data, int length);
int Length();
void SetSource_Sample(Sample& sample);
const AudioFormat* Format();
friend class Mixer;
private:
enum {
SOURCE_NONE = 0,
SOURCE_SAMPLE
} sourcetype;
Sample* sample;
};
class Channel
{
public:
Channel();
~Channel();
void Play(Stream& stream, int loop);
void SetRate(double rate);
void SetVolume(int volume);
friend class Mixer;
private:
int loop;
int offset;
double rate;
int volume;
SpeexResamplerState* resampler;
Stream* stream;
};
class Mixer
{
public:
void Init(char* device);
void Close();
private:
static void SDLCALL Callback(void* arg, Uint8* data, int length);
void MixChannel(Channel& channel, Uint8* buffer, int length);
bool MustConvert(Stream& stream);
bool Convert(SDL_AudioCVT& cvt, const Uint8* data, int length, Uint8** dataout);
SDL_AudioDeviceID deviceid;
AudioFormat format;
Sample css1samples[63];
Stream css1streams[63];
Channel channels[10];
};
extern "C"
{
#endif
void Mixer_Init(char* device);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -74,7 +74,7 @@ typedef struct {
char path[260];
uint32 var_20C;
uint8 pad_210[0x100];
char addon[15][0x80];
char addon[16][0x80];
uint32 addons; //0xB10
} rct2_install_info;

View File

@@ -39,6 +39,7 @@
#include "intro.h"
#include "language.h"
#include "map.h"
#include "mixer.h"
#include "news_item.h"
#include "object.h"
#include "osinterface.h"
@@ -88,6 +89,7 @@ __declspec(dllexport) int StartOpenRCT(HINSTANCE hInstance, HINSTANCE hPrevInsta
config_init();
language_open(gGeneral_config.language);
rct2_init();
Mixer_Init(NULL);
rct2_loop();
osinterface_free();
exit(0);

View File

@@ -33,6 +33,7 @@
#include "config.h"
#include "gfx.h"
#include "language.h"
#include "mixer.h"
#include "osinterface.h"
#include "sprites.h"
#include "string_ids.h"
@@ -503,6 +504,9 @@ static void window_options_dropdown()
switch (widgetIndex) {
case WIDX_SOUND_DROPDOWN:
audio_init2(dropdownIndex);
if (dropdownIndex < gAudioDeviceCount) {
Mixer_Init(gAudioDevices[dropdownIndex].name);
}
/*#ifdef _MSC_VER
__asm movzx ax, dropdownIndex
#else