Merge branch 'master' of https://github.com/coelckers/gzdoom into stereo3d

This commit is contained in:
Christopher Bruns 2015-12-30 17:41:49 -05:00
commit 8e237e6146
68 changed files with 5764 additions and 675 deletions

View file

@ -39,7 +39,6 @@ add_library( dumb
src/helpers/memfile.c
src/helpers/clickrem.c
src/helpers/barray.c
src/helpers/tarray.c
src/it/xmeffect.c
src/it/readxm2.c
src/it/readxm.c

View file

@ -36,24 +36,24 @@
#endif
#define DUMB_MAJOR_VERSION 0
#define DUMB_MINOR_VERSION 9
#define DUMB_REVISION_VERSION 3
#define DUMB_MAJOR_VERSION 1
#define DUMB_MINOR_VERSION 0
#define DUMB_REVISION_VERSION 0
#define DUMB_VERSION (DUMB_MAJOR_VERSION*10000 + DUMB_MINOR_VERSION*100 + DUMB_REVISION_VERSION)
#define DUMB_VERSION_STR "0.9.3"
#define DUMB_VERSION_STR "1.0.0"
#define DUMB_NAME "DUMB v" DUMB_VERSION_STR
#define DUMB_YEAR 2005
#define DUMB_MONTH 8
#define DUMB_DAY 7
#define DUMB_YEAR 2015
#define DUMB_MONTH 1
#define DUMB_DAY 17
#define DUMB_YEAR_STR2 "05"
#define DUMB_YEAR_STR4 "2005"
#define DUMB_MONTH_STR1 "8"
#define DUMB_DAY_STR1 "7"
#define DUMB_YEAR_STR2 "15"
#define DUMB_YEAR_STR4 "2015"
#define DUMB_MONTH_STR1 "1"
#define DUMB_DAY_STR1 "17"
#if DUMB_MONTH < 10
#define DUMB_MONTH_STR2 "0" DUMB_MONTH_STR1
@ -606,10 +606,6 @@ typedef void (*DUH_SIGRENDERER_GET_CURRENT_SAMPLE)(
sample_t *samples
);
typedef int32 (*DUH_SIGRENDERER_GET_POSITION)(
sigrenderer_t *sigrenderer
);
typedef void (*DUH_END_SIGRENDERER)(sigrenderer_t *sigrenderer);
typedef void (*DUH_UNLOAD_SIGDATA)(sigdata_t *sigdata);
@ -625,7 +621,6 @@ typedef struct DUH_SIGTYPE_DESC
DUH_SIGRENDERER_SET_SIGPARAM sigrenderer_set_sigparam;
DUH_SIGRENDERER_GENERATE_SAMPLES sigrenderer_generate_samples;
DUH_SIGRENDERER_GET_CURRENT_SAMPLE sigrenderer_get_current_sample;
DUH_SIGRENDERER_GET_POSITION sigrenderer_get_position;
DUH_END_SIGRENDERER end_sigrenderer;
DUH_UNLOAD_SIGDATA unload_sigdata;
}

View file

@ -33,7 +33,6 @@
#include <stddef.h>
#include "barray.h"
#include "tarray.h"
/** TO DO: THINK ABOUT THE FOLLOWING:
@ -724,21 +723,6 @@ struct DUMB_IT_SIGRENDERER
#ifdef BIT_ARRAY_BULLSHIT
/* bit array, which rows are played, only checked by pattern break or loop commands */
void * played;
/*
Loop indicator for internal processes, may also be useful for external processes
0 - Not looped
1 - Looped
-1 - Continued past loop
*/
int looped;
/*
Kept until looped
*/
LONG_LONG time_played;
void * row_timekeeper;
#endif
int32 gvz_time;

View file

@ -1,31 +0,0 @@
#ifndef _T_ARRAY_H_
#define _T_ARRAY_H_
#include <stdlib.h>
#ifndef LONG_LONG
#if defined __GNUC__ || defined __INTEL_COMPILER || defined __MWERKS__
#define LONG_LONG long long
#elif defined _MSC_VER || defined __WATCOMC__
#define LONG_LONG __int64
#elif defined __sgi
#define LONG_LONG long long
#else
#error 64-bit integer type unknown
#endif
#endif
void * timekeeping_array_create(size_t size);
void timekeeping_array_destroy(void * array);
void * timekeeping_array_dup(void * array);
void timekeeping_array_reset(void * array, size_t loop_start);
void timekeeping_array_push(void * array, size_t index, LONG_LONG time);
void timekeeping_array_bump(void * array, size_t index);
unsigned int timekeeping_array_get_count(void * array, size_t index);
LONG_LONG timekeeping_array_get_item(void * array, size_t index);
#endif

View file

@ -37,7 +37,6 @@ SOURCES += \
../../src/helpers/memfile.c \
../../src/helpers/clickrem.c \
../../src/helpers/barray.c \
../../src/helpers/tarray.c \
../../src/it/xmeffect.c \
../../src/it/readxm2.c \
../../src/it/readxm.c \
@ -109,7 +108,6 @@ HEADERS += \
../../include/internal/it.h \
../../include/internal/dumb.h \
../../include/internal/barray.h \
../../include/internal/tarray.h \
../../include/internal/aldumb.h \
../../include/internal/sinc_resampler.h \
../../include/internal/stack_alloc.h \

View file

@ -147,15 +147,7 @@ int DUMBEXPORT duh_sigrenderer_get_n_channels(DUH_SIGRENDERER *sigrenderer)
int32 DUMBEXPORT duh_sigrenderer_get_position(DUH_SIGRENDERER *sigrenderer)
{
DUH_SIGRENDERER_GET_POSITION proc;
if (!sigrenderer) return -1;
proc = sigrenderer->desc->sigrenderer_get_position;
if (proc)
return (*proc)(sigrenderer->sigrenderer);
else
return sigrenderer->pos;
return sigrenderer ? sigrenderer->pos : -1;
}

View file

@ -1,175 +0,0 @@
#include "internal/tarray.h"
#include <string.h>
/*
Structures which contain the play times of each pattern and row combination in the song,
not guaranteed to be valid for the whole song until the loop status is no longer zero.
The initial count and restart count will both be zero on song start, then both will be
incremented until the song loops. Restart count will be reset to zero on loop for all
rows which have a time equal to or greater than the loop start point, so time keeping
functions will know which timestamp the song is currently located at.
Timestamp lists are guaranteed to be allocated in blocks of 16 timestamps at a time.
*/
/*
We don't need full timekeeping because the player loop only wants the first play time
of the loop start order/row. We also don't really want full timekeeping because it
involves a lot of memory allocations, which is also slow.
*/
#undef FULL_TIMEKEEPING
typedef struct DUMB_IT_ROW_TIME
{
unsigned int count, restart_count;
#ifndef FULL_TIMEKEEPING
LONG_LONG first_time;
#else
LONG_LONG * times;
#endif
} DUMB_IT_ROW_TIME;
void * timekeeping_array_create(size_t size)
{
size_t * _size = (size_t *) calloc( 1, sizeof(size_t) + sizeof(DUMB_IT_ROW_TIME) * size );
if ( _size ) {
*_size = size;
}
return _size;
}
void timekeeping_array_destroy(void * array)
{
#ifdef FULL_TIMEKEEPING
size_t i;
size_t * size = (size_t *) array;
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
for (i = 0; i < *size; i++) {
if (s[i].times) free(s[i].times);
}
#endif
free(array);
}
void * timekeeping_array_dup(void * array)
{
size_t i;
size_t * size = (size_t *) array;
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
size_t * new_size = (size_t *) calloc( 1, sizeof(size_t) + sizeof(DUMB_IT_ROW_TIME) * *size );
if ( new_size ) {
DUMB_IT_ROW_TIME * new_s = (DUMB_IT_ROW_TIME *)(new_size + 1);
*new_size = *size;
for (i = 0; i < *size; i++) {
new_s[i].count = s[i].count;
new_s[i].restart_count = s[i].restart_count;
#ifndef FULL_TIMEKEEPING
new_s[i].first_time = s[i].first_time;
#else
if ( s[i].times ) {
size_t time_count = ( s[i].count + 15 ) & ~15;
new_s[i].times = (LONG_LONG *) malloc( sizeof(LONG_LONG) * time_count );
if ( new_s[i].times == (void *)0 ) {
timekeeping_array_destroy( new_size );
return (void *) 0;
}
memcpy( new_s[i].times, s[i].times, sizeof(LONG_LONG) * s[i].count );
}
#endif
}
}
return new_size;
}
void timekeeping_array_reset(void * array, size_t loop_start)
{
size_t i;
size_t * size = (size_t *) array;
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
DUMB_IT_ROW_TIME * s_loop_start = s + loop_start;
LONG_LONG loop_start_time;
if ( loop_start >= *size || s_loop_start->count < 1 ) return;
#ifndef FULL_TIMEKEEPING
loop_start_time = s_loop_start->first_time;
#else
loop_start_time = s_loop_start->times[0];
#endif
for ( i = 0; i < *size; i++ ) {
#ifndef FULL_TIMEKEEPING
if ( s[i].count && s[i].first_time >= loop_start_time ) {
#else
if ( s[i].count && s[i].times[0] >= loop_start_time ) {
#endif
s[i].restart_count = 0;
}
}
}
void timekeeping_array_push(void * array, size_t index, LONG_LONG time)
{
#ifdef FULL_TIMEKEEPING
size_t i;
size_t time_count;
#endif
size_t * size = (size_t *) array;
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
if (index >= *size) return;
#ifndef FULL_TIMEKEEPING
if ( !s[index].count++ )
s[index].first_time = time;
#else
time_count = ( s[index].count + 16 ) & ~15;
s[index].times = (LONG_LONG *) realloc( s[index].times, sizeof(LONG_LONG) * time_count );
s[index].times[s[index].count++] = time;
#endif
}
void timekeeping_array_bump(void * array, size_t index)
{
size_t * size = (size_t *) array;
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
if (index >= *size) return;
s[index].restart_count++;
}
unsigned int timekeeping_array_get_count(void * array, size_t index)
{
size_t * size = (size_t *) array;
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
if (index >= *size) return 0;
return s[index].count;
}
LONG_LONG timekeeping_array_get_item(void * array, size_t index)
{
size_t * size = (size_t *) array;
DUMB_IT_ROW_TIME * s = (DUMB_IT_ROW_TIME *)(size + 1);
if (index >= *size || s[index].restart_count >= s[index].count) return 0;
#ifndef FULL_TIMEKEEPING
return s[index].first_time;
#else
return s[index].times[s[index].restart_count];
#endif
}

View file

@ -290,12 +290,15 @@ static int it_read_envelope(IT_ENVELOPE *envelope, DUMBFILE *f)
envelope->flags = dumbfile_getc(f);
envelope->n_nodes = dumbfile_getc(f);
if(envelope->n_nodes > 25) {
TRACE("IT error: wrong number of envelope nodes (%d)\n", envelope->n_nodes);
envelope->n_nodes = 0;
return -1;
}
envelope->loop_start = dumbfile_getc(f);
envelope->loop_end = dumbfile_getc(f);
envelope->sus_loop_start = dumbfile_getc(f);
envelope->sus_loop_end = dumbfile_getc(f);
if (envelope->n_nodes > 25)
envelope->n_nodes = 25;
for (n = 0; n < envelope->n_nodes; n++) {
envelope->node_y[n] = dumbfile_getc(f);
envelope->node_t[n] = dumbfile_igetw(f);

View file

@ -352,10 +352,6 @@ static DUMB_IT_SIGRENDERER *dup_sigrenderer(DUMB_IT_SIGRENDERER *src, int n_chan
#ifdef BIT_ARRAY_BULLSHIT
dst->played = bit_array_dup(src->played);
dst->looped = src->looped;
dst->time_played = src->time_played;
dst->row_timekeeper = timekeeping_array_dup(src->row_timekeeper);
#endif
dst->gvz_time = src->gvz_time;
@ -2221,9 +2217,6 @@ Yxy This uses a table 4 times larger (hence 4 times slower) than
bit_array_set(sigrenderer->played, sigrenderer->order * 256 + sigrenderer->row);
#endif
sigrenderer->speed = 0;
#ifdef BIT_ARRAY_BULLSHIT
sigrenderer->looped = 1;
#endif
if (sigrenderer->callbacks->xm_speed_zero && (*sigrenderer->callbacks->xm_speed_zero)(sigrenderer->callbacks->xm_speed_zero_data))
return 1;
}
@ -4341,8 +4334,6 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer)
/* Fix play tracking and timekeeping for orders containing skip commands */
for (n = 0; n < 256; n++) {
bit_array_set(sigrenderer->played, sigrenderer->processorder * 256 + n);
timekeeping_array_push(sigrenderer->row_timekeeper, sigrenderer->processorder * 256 + n, sigrenderer->time_played);
timekeeping_array_bump(sigrenderer->row_timekeeper, sigrenderer->processorder * 256 + n);
}
#endif
}
@ -4367,9 +4358,6 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer)
&& bit_array_test(sigrenderer->played, sigrenderer->processorder * 256 + sigrenderer->processrow)
#endif
) {
#ifdef BIT_ARRAY_BULLSHIT
sigrenderer->looped = 1;
#endif
if (sigrenderer->callbacks->loop) {
if ((*sigrenderer->callbacks->loop)(sigrenderer->callbacks->loop_data))
return 1;
@ -4413,13 +4401,6 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer)
}
}
#ifdef BIT_ARRAY_BULLSHIT
if (sigrenderer->looped == 0) {
timekeeping_array_push(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row, sigrenderer->time_played);
}
timekeeping_array_bump(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row);
#endif
if (!(sigdata->flags & IT_WAS_A_669))
reset_effects(sigrenderer);
@ -4471,9 +4452,6 @@ static int process_tick(DUMB_IT_SIGRENDERER *sigrenderer)
sigrenderer->gvz_time += (int)(t >> 16);
sigrenderer->gvz_sub_time = (int)t & 65535;
if (sigrenderer->gvz_time >= 65536 * 12) {
#ifdef BIT_ARRAY_BULLSHIT
sigrenderer->looped = 1;
#endif
if ((*sigrenderer->callbacks->global_volume_zero)(sigrenderer->callbacks->global_volume_zero_data))
return 1;
}
@ -5288,10 +5266,6 @@ static DUMB_IT_SIGRENDERER *init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_cha
#ifdef BIT_ARRAY_BULLSHIT
sigrenderer->played = bit_array_create(sigdata->n_orders * 256);
sigrenderer->looped = 0;
sigrenderer->time_played = 0;
sigrenderer->row_timekeeper = timekeeping_array_create(sigdata->n_orders * 256);
#endif
{
@ -5310,8 +5284,6 @@ static DUMB_IT_SIGRENDERER *init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_cha
/* Fix for played order detection for songs which have skips at the start of the orders list */
for (n = 0; n < 256; n++) {
bit_array_set(sigrenderer->played, order * 256 + n);
timekeeping_array_push(sigrenderer->row_timekeeper, order * 256 + n, 0);
timekeeping_array_bump(sigrenderer->row_timekeeper, order * 256 + n);
}
#endif
}
@ -5324,6 +5296,10 @@ static DUMB_IT_SIGRENDERER *init_sigrenderer(DUMB_IT_SIGDATA *sigdata, int n_cha
sigrenderer->time_left = 0;
sigrenderer->sub_time_left = 0;
#ifdef BIT_ARRAY_BULLSHIT
sigrenderer->played = bit_array_create(sigdata->n_orders * 256);
#endif
sigrenderer->gvz_time = 0;
sigrenderer->gvz_sub_time = 0;
@ -5482,10 +5458,6 @@ static sigrenderer_t *it_start_sigrenderer(DUH *duh, sigdata_t *vsigdata, int n_
while (pos > 0 && pos >= sigrenderer->time_left) {
render(sigrenderer, 0, 1.0f, 0, sigrenderer->time_left, NULL);
#ifdef BIT_ARRAY_BULLSHIT
sigrenderer->time_played += (LONG_LONG)sigrenderer->time_left << 16;
#endif
pos -= sigrenderer->time_left;
sigrenderer->time_left = 0;
@ -5498,10 +5470,6 @@ static sigrenderer_t *it_start_sigrenderer(DUH *duh, sigdata_t *vsigdata, int n_
render(sigrenderer, 0, 1.0f, 0, pos, NULL);
sigrenderer->time_left -= pos;
#ifdef BIT_ARRAY_BULLSHIT
sigrenderer->time_played += (LONG_LONG)pos << 16;
#endif
return sigrenderer;
}
@ -5517,7 +5485,6 @@ static int32 it_sigrenderer_get_samples(
int32 pos;
int dt;
int32 todo;
int ret;
LONG_LONG t;
if (sigrenderer->order < 0) return 0; // problematic
@ -5531,7 +5498,7 @@ static int32 it_sigrenderer_get_samples(
if (!samples) volume = 0;
for (;;) {
todo = (int32)((((LONG_LONG)sigrenderer->time_left << 16) | sigrenderer->sub_time_left) / dt);
todo = (long)((((LONG_LONG)sigrenderer->time_left << 16) | sigrenderer->sub_time_left) / dt);
if (todo >= size)
break;
@ -5545,28 +5512,9 @@ static int32 it_sigrenderer_get_samples(
sigrenderer->sub_time_left = (int32)t & 65535;
sigrenderer->time_left += (int32)(t >> 16);
#ifdef BIT_ARRAY_BULLSHIT
sigrenderer->time_played += (LONG_LONG)todo * dt;
#endif
ret = process_tick(sigrenderer);
if (ret) {
if (process_tick(sigrenderer)) {
sigrenderer->order = -1;
sigrenderer->row = -1;
}
#ifdef BIT_ARRAY_BULLSHIT
if (sigrenderer->looped == 1) {
sigrenderer->looped = -1;
size = 0;
timekeeping_array_reset(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row);
sigrenderer->time_played = timekeeping_array_get_item(sigrenderer->row_timekeeper, sigrenderer->order * 256 + sigrenderer->row);
break;
}
#endif
if (ret) {
return pos;
}
}
@ -5579,10 +5527,6 @@ static int32 it_sigrenderer_get_samples(
sigrenderer->sub_time_left = (int32)t & 65535;
sigrenderer->time_left += (int32)(t >> 16);
#ifdef BIT_ARRAY_BULLSHIT
sigrenderer->time_played += (LONG_LONG)size * dt;
#endif
if (samples)
dumb_remove_clicks_array(sigrenderer->n_channels, sigrenderer->click_remover, samples, pos, 512.0f / delta);
@ -5634,8 +5578,6 @@ void _dumb_it_end_sigrenderer(sigrenderer_t *vsigrenderer)
#ifdef BIT_ARRAY_BULLSHIT
bit_array_destroy(sigrenderer->played);
timekeeping_array_destroy(sigrenderer->row_timekeeper);
#endif
free(vsigrenderer);
@ -5644,17 +5586,6 @@ void _dumb_it_end_sigrenderer(sigrenderer_t *vsigrenderer)
#ifdef BIT_ARRAY_BULLSHIT
static int32 it_sigrenderer_get_position(sigrenderer_t *vsigrenderer)
{
DUMB_IT_SIGRENDERER *sigrenderer = vsigrenderer;
return (int32)(sigrenderer->time_played >> 16);
}
#endif
DUH_SIGTYPE_DESC _dumb_sigtype_it = {
SIGTYPE_IT,
NULL,
@ -5662,11 +5593,6 @@ DUH_SIGTYPE_DESC _dumb_sigtype_it = {
NULL,
&it_sigrenderer_get_samples,
&it_sigrenderer_get_current_sample,
#ifdef BIT_ARRAY_BULLSHIT
&it_sigrenderer_get_position,
#else
NULL,
#endif
&_dumb_it_end_sigrenderer,
&_dumb_it_unload_sigdata
};

View file

@ -320,6 +320,8 @@ static DUMB_IT_SIGDATA *it_amf_load_sigdata(DUMBFILE *f, int * version)
free( sigdata );
return NULL;
}
sigdata->n_pchannels = nchannels;
memset( sigdata->channel_volume, 64, DUMB_IT_N_CHANNELS );

View file

@ -439,6 +439,7 @@ static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f)
}
if (dumbfile_seek(f, 352, DFS_SEEK_SET)) {
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
@ -451,12 +452,14 @@ static DUMB_IT_SIGDATA *it_ptm_load_sigdata(DUMBFILE *f)
}
if (dumbfile_seek(f, 608, DFS_SEEK_SET)) {
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}
for (n = 0; n < sigdata->n_samples; n++) {
if (it_ptm_read_sample_header(&sigdata->sample[n], &component[n_components].offset, f)) {
free(component);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}

View file

@ -1197,6 +1197,7 @@ static DUMB_IT_SIGDATA *it_xm_load_sigdata(DUMBFILE *f, int * version)
sigdata->instrument = malloc(sigdata->n_instruments * sizeof(*sigdata->instrument));
if (!sigdata->instrument) {
free(roguebytes);
_dumb_it_unload_sigdata(sigdata);
return NULL;
}

View file

@ -118,7 +118,6 @@
<ClCompile Include="..\..\src\helpers\sampbuf.c" />
<ClCompile Include="..\..\src\helpers\silence.c" />
<ClCompile Include="..\..\src\helpers\stdfile.c" />
<ClCompile Include="..\..\src\helpers\tarray.c" />
<ClCompile Include="..\..\src\it\itmisc.c" />
<ClCompile Include="..\..\src\it\itorder.c" />
<ClCompile Include="..\..\src\it\itrender.c" />
@ -210,7 +209,6 @@
<ClInclude Include="..\..\include\internal\lpc.h" />
<ClInclude Include="..\..\include\internal\riff.h" />
<ClInclude Include="..\..\include\internal\stack_alloc.h" />
<ClInclude Include="..\..\include\internal\tarray.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View file

@ -279,9 +279,6 @@
<ClCompile Include="..\..\src\helpers\resampler.c">
<Filter>src\helpers</Filter>
</ClCompile>
<ClCompile Include="..\..\src\helpers\tarray.c">
<Filter>src\helpers</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\include\dumb.h">
@ -314,9 +311,6 @@
<ClInclude Include="..\..\include\internal\resampler.h">
<Filter>include\internal</Filter>
</ClInclude>
<ClInclude Include="..\..\include\internal\tarray.h">
<Filter>include\internal</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<CustomBuild Include="..\..\src\helpers\resamp3.inc">

View file

@ -188,6 +188,7 @@ else( WIN32 )
if( GTK2_FOUND )
set( ZDOOM_LIBS ${ZDOOM_LIBS} ${GTK2_LIBRARIES} )
include_directories( ${GTK2_INCLUDE_DIRS} )
link_directories( ${GTK2_LIBRARY_DIRS} )
else( GTK2_FOUND )
set( NO_GTK ON )
endif( GTK2_FOUND )
@ -449,6 +450,22 @@ else( SSE_MATTERS )
set( BACKPATCH 0 )
endif( SSE_MATTERS )
if( X64 )
set( HAVE_MMX 1 )
else( X64 )
set( SAFE_CMAKE_C_FLAGS ${CMAKE_C_FLAGS} )
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mmmx")
endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
CHECK_CXX_SOURCE_COMPILES("#include <mmintrin.h>
int main(void) { __m64 v = _m_from_int(0); }"
HAVE_MMX)
set( CMAKE_C_FLAGS ${SAFE_CMAKE_C_FLAGS} )
endif( X64 )
# Set up flags for GCC
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
@ -581,10 +598,6 @@ endif( NOT DYN_FLUIDSYNTH )
# Start defining source files for ZDoom
set( PLAT_WIN32_SOURCES
gl/hqnx_asm/hq2x_asm.cpp
gl/hqnx_asm/hq3x_asm.cpp
gl/hqnx_asm/hq4x_asm.cpp
gl/hqnx_asm/hqnx_asm_Image.cpp
win32/eaxedit.cpp
win32/fb_d3d9.cpp
win32/fb_d3d9_wipe.cpp
@ -668,6 +681,25 @@ else( WIN32 )
set( OTHER_SYSTEM_SOURCES ${PLAT_WIN32_SOURCES} ${PLAT_OSX_SOURCES} ${PLAT_COCOA_SOURCES} )
endif( WIN32 )
if( HAVE_MMX )
add_definitions( -DHAVE_MMX=1 )
set( SYSTEM_SOURCES ${SYSTEM_SOURCES}
gl/hqnx_asm/hq2x_asm.cpp
gl/hqnx_asm/hq3x_asm.cpp
gl/hqnx_asm/hq4x_asm.cpp
gl/hqnx_asm/hqnx_asm_Image.cpp)
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
set_source_files_properties(
gl/hqnx_asm/hq2x_asm.cpp
gl/hqnx_asm/hq3x_asm.cpp
gl/hqnx_asm/hq4x_asm.cpp
gl/textures/gl_hqresize.cpp
PROPERTIES COMPILE_FLAGS "-mmmx" )
endif( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
endif( HAVE_MMX )
if( NOT ASM_SOURCES )
set( ASM_SOURCES "" )
endif( NOT ASM_SOURCES )
@ -947,6 +979,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
nodebuild_extract.cpp
nodebuild_gl.cpp
nodebuild_utility.cpp
pathexpander.cpp
p_3dfloors.cpp
p_3dmidtex.cpp
p_acs.cpp
@ -1185,6 +1218,7 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
sound/music_fluidsynth_mididevice.cpp
sound/music_softsynth_mididevice.cpp
sound/music_timidity_mididevice.cpp
sound/music_wildmidi_mididevice.cpp
sound/music_win_mididevice.cpp
sound/oalsound.cpp
sound/sndfile_decoder.cpp
@ -1228,6 +1262,11 @@ add_executable( zdoom WIN32 MACOSX_BUNDLE
timidity/playmidi.cpp
timidity/resample.cpp
timidity/timidity.cpp
wildmidi/file_io.cpp
wildmidi/gus_pat.cpp
wildmidi/reverb.cpp
wildmidi/wildmidi_lib.cpp
wildmidi/wm_error.cpp
xlat/parse_xlat.cpp
fragglescript/t_fspic.cpp
fragglescript/t_func.cpp
@ -1365,6 +1404,8 @@ source_group("Audio Files\\OPL Synth" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURC
source_group("Audio Files\\OPL Synth\\DOSBox" FILES oplsynth/dosbox/opl.cpp oplsynth/dosbox/opl.h)
source_group("Audio Files\\Timidity\\Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/timidity/.+\\.h$")
source_group("Audio Files\\Timidity\\Source" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/timidity/.+\\.cpp$")
source_group("Audio Files\\WildMidi\\Headers" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/wildmidi/.+\\.h$")
source_group("Audio Files\\WildMidi\\Source" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/wildmidi/.+\\.cpp$")
source_group("Decorate++" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/thingdef/.+")
source_group("FraggleScript" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/fragglescript/.+")
source_group("Games\\Doom Game" REGULAR_EXPRESSION "^${CMAKE_CURRENT_SOURCE_DIR}/g_doom/.+")

View file

@ -21,7 +21,9 @@
#ifndef __HQNX_H__
#define __HQNX_H__
#ifdef _MSC_VER
#pragma warning(disable:4799)
#endif // _MSC_VER
#include "hqnx_asm_Image.h"

View file

@ -24,7 +24,9 @@
#include <stdio.h>
#pragma once
#ifdef _MSC_VER
#pragma warning(disable: 4103)
#endif // _MSC_VER
#pragma pack(1)
namespace HQnX_asm

View file

@ -1261,7 +1261,7 @@ void GLWall::ClipFFloors(seg_t * seg, F3DFloor * ffloor, sector_t * frontsector,
F3DFloor * rover=frontffloors[i];
if (!(rover->flags&FF_EXISTS)) continue;
if (!(rover->flags&FF_RENDERSIDES)) continue;
if ((rover->flags&flags)!=flags) continue;
if ((rover->flags&(FF_SWIMMABLE|FF_TRANSLUCENT))!=flags) continue;
fixed_t ff_topleft;
fixed_t ff_topright;

View file

@ -322,6 +322,11 @@ void GLWall::RenderTranslucentWall()
// and until that changes I won't fix this code for the new blending modes!
bool isadditive = RenderStyle == STYLE_Add;
if (gl_fixedcolormap == CM_DEFAULT && gl_lights && (gl.flags & RFL_BUFFER_STORAGE))
{
SetupLights();
}
if (!transparent) gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_threshold);
else gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
if (isadditive) gl_RenderState.BlendFunc(GL_SRC_ALPHA,GL_ONE);

View file

@ -57,4 +57,18 @@ CUSTOM_CVAR (Float, vid_contrast, 1.f, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
// when they are actually valid.
void gl_SetupMenu()
{
#ifndef HAVE_MMX
FOptionValues **opt = OptionValues.CheckKey("HqResizeModes");
if (opt != NULL)
{
for(int i = (*opt)->mValues.Size()-1; i>=0; i--)
{
// Delete HQnX resize modes for non MSVC targets
if ((*opt)->mValues[i].Value >= 7.0)
{
(*opt)->mValues.Delete(i);
}
}
}
#endif
}

View file

@ -49,7 +49,7 @@
#include <errno.h>
#include <stdarg.h>
#include <signal.h>
#if !defined(__APPLE__)
#if !defined(__APPLE__) && !defined(__FreeBSD__)
#include <malloc.h>
#endif
#include <time.h>

View file

@ -40,13 +40,17 @@
#include "gl/textures/gl_texture.h"
#include "c_cvars.h"
#include "gl/hqnx/hqx.h"
#ifdef _MSC_VER
#ifdef HAVE_MMX
#include "gl/hqnx_asm/hqnx_asm.h"
#endif
CUSTOM_CVAR(Int, gl_texture_hqresize, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
#ifdef HAVE_MMX
if (self < 0 || self > 9)
#else
if (self < 0 || self > 6)
#endif
self = 0;
GLRenderer->FlushTextures();
}
@ -182,8 +186,7 @@ static unsigned char *scaleNxHelper( void (*scaleNxFunction) ( uint32* , uint32*
return newBuffer;
}
// [BB] hqnx scaling is only supported with the MS compiler.
#ifdef _MSC_VER
#ifdef HAVE_MMX
static unsigned char *hqNxAsmHelper( void (*hqNxFunction) ( int*, unsigned char*, int, int, int ),
const int N,
unsigned char *inputBuffer,
@ -281,7 +284,7 @@ unsigned char *gl_CreateUpsampledTextureBuffer ( const FTexture *inputTexture, u
outWidth = inWidth;
outHeight = inHeight;
int type = gl_texture_hqresize;
#ifdef _MSC_VER
#ifdef HAVE_MMX
// ASM-hqNx does not preserve the alpha channel so fall back to C-version for such textures
if (!hasAlpha && type > 3 && type <= 6)
{
@ -303,7 +306,7 @@ unsigned char *gl_CreateUpsampledTextureBuffer ( const FTexture *inputTexture, u
return hqNxHelper( &hq3x_32, 3, inputBuffer, inWidth, inHeight, outWidth, outHeight );
case 6:
return hqNxHelper( &hq4x_32, 4, inputBuffer, inWidth, inHeight, outWidth, outHeight );
#ifdef _MSC_VER
#ifdef HAVE_MMX
case 7:
return hqNxAsmHelper( &HQnX_asm::hq2x_32, 2, inputBuffer, inWidth, inHeight, outWidth, outHeight );
case 8:

View file

@ -1264,7 +1264,7 @@ static int UseInventory (AActor *activator, const char *type)
//
//============================================================================
static int CheckInventory (AActor *activator, const char *type)
static int CheckInventory (AActor *activator, const char *type, bool max)
{
if (activator == NULL || type == NULL)
return 0;
@ -1275,11 +1275,26 @@ static int CheckInventory (AActor *activator, const char *type)
}
else if (stricmp (type, "Health") == 0)
{
if (max)
{
if (activator->IsKindOf (RUNTIME_CLASS (APlayerPawn)))
return static_cast<APlayerPawn *>(activator)->MaxHealth;
else
return activator->SpawnHealth();
}
return activator->health;
}
const PClass *info = PClass::FindClass (type);
AInventory *item = activator->FindInventory (info);
if (max)
{
if (item)
return item->MaxAmount;
else
return ((AInventory *)GetDefaultByType (info))->MaxAmount;
}
return item ? item->Amount : 0;
}
@ -4442,6 +4457,7 @@ enum EACSFunctions
ACSF_GetActorRoll,
ACSF_QuakeEx,
ACSF_Warp, // 92
ACSF_GetMaxInventory,
/* Zandronum's - these must be skipped when we reach 99!
-100:ResetMap(0),
@ -5915,6 +5931,13 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound)
}
return false;
}
case ACSF_GetMaxInventory:
actor = SingleActorFromTID(args[0], activator);
if (actor != NULL)
{
return CheckInventory(actor, FBehavior::StaticLookupString(args[1]), true);
}
break;
default:
break;
@ -8339,17 +8362,17 @@ scriptwait:
break;
case PCD_CHECKINVENTORY:
STACK(1) = CheckInventory (activator, FBehavior::StaticLookupString (STACK(1)));
STACK(1) = CheckInventory (activator, FBehavior::StaticLookupString (STACK(1)), false);
break;
case PCD_CHECKACTORINVENTORY:
STACK(2) = CheckInventory (SingleActorFromTID(STACK(2), NULL),
FBehavior::StaticLookupString (STACK(1)));
FBehavior::StaticLookupString (STACK(1)), false);
sp--;
break;
case PCD_CHECKINVENTORYDIRECT:
PushToStack (CheckInventory (activator, FBehavior::StaticLookupString (TAGSTR(uallong(pc[0])))));
PushToStack (CheckInventory (activator, FBehavior::StaticLookupString (TAGSTR(uallong(pc[0]))), false));
pc += 1;
break;

View file

@ -1347,9 +1347,10 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply
int rootnode = npc->ConversationRoot;
if (reply->NextNode < 0)
{
npc->Conversation = StrifeDialogues[rootnode - reply->NextNode - 1];
if (gameaction != ga_slideshow)
unsigned next = (unsigned)(rootnode - reply->NextNode - 1);
if (gameaction != ga_slideshow && next < StrifeDialogues.Size())
{
npc->Conversation = StrifeDialogues[next];
P_StartConversation (npc, player->mo, player->ConversationFaceTalker, false);
return;
}

View file

@ -288,16 +288,16 @@ bool P_TestActivateLine (line_t *line, AActor *mo, int side, int activationType)
}
}
if (activationType == SPAC_Use && (lineActivation & SPAC_MUse) && !mo->player && mo->flags4 & MF4_CANUSEWALLS)
{
return true;
}
if (activationType == SPAC_Push && (lineActivation & SPAC_MPush) && !mo->player && mo->flags2 & MF2_PUSHWALL)
{
return true;
}
if ((lineActivation & activationType) == 0)
{
if (activationType == SPAC_Use && (lineActivation & SPAC_MUse) && !mo->player && mo->flags4 & MF4_CANUSEWALLS)
{
return true;
}
if (activationType == SPAC_Push && (lineActivation & SPAC_MPush) && !mo->player && mo->flags2 & MF2_PUSHWALL)
{
return true;
}
if (activationType != SPAC_MCross || lineActivation != SPAC_Cross)
{
return false;

View file

@ -785,7 +785,7 @@ public:
bool strifetrans = false;
bool strifetrans2 = false;
FString arg0str, arg1str;
int lineid; // forZDoomTranslated namespace
int lineid = -1; // forZDoomTranslated namespace
FString tagstring;
memset(ld, 0, sizeof(*ld));
@ -1082,7 +1082,7 @@ public:
maplinedef_t mld;
memset(&mld, 0, sizeof(mld));
mld.special = ld->special;
mld.tag = lineid;
mld.tag = ld->args[0];
P_TranslateLineDef(ld, &mld);
ld->flags = saved | (ld->flags&(ML_MONSTERSCANACTIVATE|ML_REPEAT_SPECIAL|ML_FIRSTSIDEONLY));
}

View file

@ -566,6 +566,10 @@ void APlayerPawn::Serialize (FArchive &arc)
{
arc << AirCapacity;
}
if (SaveVersion >= 4526)
{
arc << ViewHeight;
}
}
//===========================================================================

134
src/pathexpander.cpp Normal file
View file

@ -0,0 +1,134 @@
/*
** pathexpander.cpp
** Utility class for expanding a given path with a range of directories
**
**---------------------------------------------------------------------------
** Copyright 2015 Christoph Oelckers
** All rights reserved.
**
** 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.
**---------------------------------------------------------------------------
**
*/
#include "pathexpander.h"
#include "cmdlib.h"
#include "w_wad.h"
//============================================================================
//
//
//
//============================================================================
static FString BuildPath(const FString &base, const char *name)
{
FString current;
if (base.IsNotEmpty())
{
current = base;
if (current[current.Len() - 1] != '/') current += '/';
}
current += name;
return current;
}
//============================================================================
//
// This is meant to find and open files for reading.
//
//============================================================================
FileReader *PathExpander::openFileReader(const char *name, int *plumpnum)
{
FileReader *fp;
FString current_filename;
if (!name || !(*name))
{
return 0;
}
/* First try the given name */
current_filename = name;
FixPathSeperator(current_filename);
if (openmode != OM_FILE)
{
int lumpnum = Wads.CheckNumForFullName(current_filename);
if (lumpnum >= 0)
{
fp = Wads.ReopenLumpNum(lumpnum);
if (plumpnum) *plumpnum = lumpnum;
return fp;
}
if (openmode == OM_LUMP) // search the path list when not loading the main config
{
for (unsigned int plp = PathList.Size(); plp-- != 0; )
{ /* Try along the path then */
current_filename = BuildPath(PathList[plp], name);
lumpnum = Wads.CheckNumForFullName(current_filename);
if (lumpnum >= 0)
{
fp = Wads.ReopenLumpNum(lumpnum);
if (plumpnum) *plumpnum = lumpnum;
return fp;
}
}
return NULL;
}
}
if (plumpnum) *plumpnum = -1;
fp = new FileReader;
if (fp->Open(current_filename)) return fp;
if (name[0] != '/')
{
for (unsigned int plp = PathList.Size(); plp-- != 0; )
{ /* Try along the path then */
current_filename = BuildPath(PathList[plp], name);
if (fp->Open(current_filename)) return fp;
}
}
delete fp;
/* Nothing could be opened. */
return NULL;
}
/* This adds a directory to the path list */
void PathExpander::addToPathlist(const char *s)
{
FString copy = s;
FixPathSeperator(copy);
PathList.Push(copy);
}
void PathExpander::clearPathlist()
{
PathList.Clear();
}

31
src/pathexpander.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef __PATHEXPANDER_H
#define __PATHEXPANDER_H
#include "tarray.h"
#include "zstring.h"
#include "files.h"
class PathExpander
{
TArray<FString> PathList;
public:
int openmode;
enum
{
OM_FILEORLUMP = 0,
OM_LUMP,
OM_FILE
};
PathExpander(int om = OM_FILEORLUMP)
{
openmode = om;
}
void addToPathlist(const char *s);
void clearPathlist();
FileReader *openFileReader(const char *name, int *plumpnum);
};
#endif

View file

@ -1372,6 +1372,7 @@ static void S_AddSNDINFO (int lump)
else if (sc.Compare("default")) MidiDevices[nm] = MDEV_DEFAULT;
else if (sc.Compare("fluidsynth")) MidiDevices[nm] = MDEV_FLUIDSYNTH;
else if (sc.Compare("gus")) MidiDevices[nm] = MDEV_GUS;
else if (sc.Compare("wildmidi")) MidiDevices[nm] = MDEV_WILDMIDI;
else sc.ScriptError("Unknown MIDI device %s\n", sc.String);
}
break;

View file

@ -394,6 +394,7 @@ enum EMidiDevice
MDEV_TIMIDITY = 3,
MDEV_FLUIDSYNTH = 4,
MDEV_GUS = 5,
MDEV_WILDMIDI = 6,
};
typedef TMap<FName, FName> MusicAliasMap;

View file

@ -44,7 +44,7 @@ extern HWND Window;
#define FALSE 0
#define TRUE 1
#endif
#ifdef __APPLE__
#if defined(__FreeBSD__) || defined(__APPLE__)
#include <stdlib.h>
#elif __sun
#include <alloca.h>

View file

@ -162,7 +162,7 @@ void I_InitMusic (void)
if (!setatterm)
{
setatterm = true;
atterm (I_ShutdownMusic);
atterm (I_ShutdownMusicExit);
#ifndef _WIN32
signal (SIGCHLD, ChildSigHandler);
@ -178,7 +178,7 @@ void I_InitMusic (void)
//
//==========================================================================
void I_ShutdownMusic(void)
void I_ShutdownMusic(bool onexit)
{
if (MusicDown)
return;
@ -189,11 +189,17 @@ void I_ShutdownMusic(void)
assert (currSong == NULL);
}
Timidity::FreeAll();
if (onexit) WildMidi_Shutdown();
#ifdef _WIN32
I_ShutdownMusicWin32();
#endif // _WIN32
}
void I_ShutdownMusicExit()
{
I_ShutdownMusic(true);
}
//==========================================================================
//
@ -280,6 +286,10 @@ void MusInfo::FluidSettingStr(const char *, const char *)
{
}
void MusInfo::WildMidiSetOption(int opt, int set)
{
}
FString MusInfo::GetStats()
{
return "No stats available for this song";

View file

@ -43,7 +43,8 @@ struct FOptionValues;
// MUSIC I/O
//
void I_InitMusic ();
void I_ShutdownMusic ();
void I_ShutdownMusic (bool onexit = false);
void I_ShutdownMusicExit ();
void I_BuildMIDIMenuList (FOptionValues *);
void I_UpdateMusic ();
@ -81,6 +82,7 @@ public:
virtual void FluidSettingInt(const char *setting, int value); // FluidSynth settings
virtual void FluidSettingNum(const char *setting, double value); // "
virtual void FluidSettingStr(const char *setting, const char *value); // "
virtual void WildMidiSetOption(int opt, int set);
void Start(bool loop, float rel_vol = -1.f, int subsong = 0);

View file

@ -24,6 +24,7 @@
#include "i_music.h"
#include "s_sound.h"
#include "files.h"
#include "wildmidi/wildmidi_lib.h"
void I_InitMusicWin32 ();
void I_ShutdownMusicWin32 ();
@ -101,6 +102,7 @@ public:
virtual void FluidSettingInt(const char *setting, int value);
virtual void FluidSettingNum(const char *setting, double value);
virtual void FluidSettingStr(const char *setting, const char *value);
virtual void WildMidiSetOption(int opt, int set);
virtual bool Preprocess(MIDIStreamer *song, bool looping);
virtual FString GetStats();
};
@ -218,7 +220,6 @@ protected:
#endif
};
// Base class for software synthesizer MIDI output devices ------------------
class SoftSynthMIDIDevice : public MIDIDevice
@ -331,6 +332,27 @@ protected:
FILE *File;
};
// WildMidi implementation of a MIDI device ---------------------------------
class WildMIDIDevice : public SoftSynthMIDIDevice
{
public:
WildMIDIDevice();
~WildMIDIDevice();
int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
void PrecacheInstruments(const WORD *instruments, int count);
FString GetStats();
protected:
WildMidi_Renderer *Renderer;
void HandleEvent(int status, int parm1, int parm2);
void HandleLongEvent(const BYTE *data, int len);
void ComputeOutput(float *buffer, int len);
void WildMidiSetOption(int opt, int set);
};
// FluidSynth implementation of a MIDI device -------------------------------
#ifdef HAVE_FLUIDSYNTH
@ -427,6 +449,7 @@ public:
void FluidSettingInt(const char *setting, int value);
void FluidSettingNum(const char *setting, double value);
void FluidSettingStr(const char *setting, const char *value);
void WildMidiSetOption(int opt, int set);
void CreateSMF(TArray<BYTE> &file, int looplimit=0);
protected:
@ -546,7 +569,7 @@ protected:
struct TrackInfo;
void ProcessInitialMetaEvents ();
DWORD *SendCommand (DWORD *event, TrackInfo *track, DWORD delay);
DWORD *SendCommand (DWORD *event, TrackInfo *track, DWORD delay, ptrdiff_t room, bool &sysex_noroom);
TrackInfo *FindNextDue ();
BYTE *MusHeader;

View file

@ -11,9 +11,9 @@ static DWORD nummididevices;
static bool nummididevicesset;
#ifdef HAVE_FLUIDSYNTH
#define NUM_DEF_DEVICES 5
#define NUM_DEF_DEVICES 6
#else
#define NUM_DEF_DEVICES 4
#define NUM_DEF_DEVICES 5
#endif
static void AddDefaultMidiDevices(FOptionValues *opt)
@ -33,8 +33,10 @@ static void AddDefaultMidiDevices(FOptionValues *opt)
pair[p+1].Value = -3.0;
pair[p+2].Text = "TiMidity++";
pair[p+2].Value = -2.0;
pair[p+3].Text = "Sound System";
pair[p+3].Value = -1.0;
pair[p+3].Text = "WildMidi";
pair[p+3].Value = -6.0;
pair[p+4].Text = "Sound System";
pair[p+4].Value = -1.0;
}
@ -70,7 +72,7 @@ CUSTOM_CVAR (Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
if (!nummididevicesset)
return;
if ((self >= (signed)nummididevices) || (self < -5))
if ((self >= (signed)nummididevices) || (self < -6))
{
Printf ("ID out of range. Using default device.\n");
self = 0;
@ -166,6 +168,7 @@ CCMD (snd_listmididevices)
MIDIOUTCAPS caps;
MMRESULT res;
PrintMidiDevice (-6, "WildMidi", MOD_SWSYNTH, 0);
#ifdef HAVE_FLUIDSYNTH
PrintMidiDevice (-5, "FluidSynth", MOD_SWSYNTH, 0);
#endif
@ -196,8 +199,8 @@ CCMD (snd_listmididevices)
CUSTOM_CVAR(Int, snd_mididevice, -1, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
{
if (self < -5)
self = -5;
if (self < -6)
self = -6;
else if (self > -1)
self = -1;
else
@ -211,6 +214,7 @@ void I_BuildMIDIMenuList (FOptionValues *opt)
CCMD (snd_listmididevices)
{
Printf("%s-6. WildMidi\n", -6 == snd_mididevice ? TEXTCOLOR_BOLD : "");
#ifdef HAVE_FLUIDSYNTH
Printf("%s-5. FluidSynth\n", -5 == snd_mididevice ? TEXTCOLOR_BOLD : "");
#endif

View file

@ -240,6 +240,7 @@ EMidiDevice MIDIStreamer::SelectMIDIDevice(EMidiDevice device)
#ifdef HAVE_FLUIDSYNTH
case -5: return MDEV_FLUIDSYNTH;
#endif
case -6: return MDEV_WILDMIDI;
default:
#ifdef _WIN32
return MDEV_MMAPI;
@ -292,6 +293,9 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const
case MDEV_TIMIDITY:
return new TimidityPPMIDIDevice;
case MDEV_WILDMIDI:
return new WildMIDIDevice;
default:
return NULL;
}
@ -622,6 +626,21 @@ void MIDIStreamer::FluidSettingStr(const char *setting, const char *value)
}
//==========================================================================
//
// MIDIDeviceStreamer :: WildMidiSetOption
//
//==========================================================================
void MIDIStreamer::WildMidiSetOption(int opt, int set)
{
if (MIDI != NULL)
{
MIDI->WildMidiSetOption(opt, set);
}
}
//==========================================================================
//
// MIDIStreamer :: OutputVolume
@ -1192,9 +1211,15 @@ void MIDIStreamer::CreateSMF(TArray<BYTE> &file, int looplimit)
len--;
file.Push(MIDI_SYSEX);
WriteVarLen(file, len);
memcpy(&file[file.Reserve(len - 1)], bytes, len);
running_status = 255;
memcpy(&file[file.Reserve(len)], bytes + 1, len);
}
else
{
file.Push(MIDI_SYSEXEND);
WriteVarLen(file, len);
memcpy(&file[file.Reserve(len)], bytes, len);
}
running_status = 255;
}
else if (MEVT_EVENTTYPE(event[2]) == 0)
{
@ -1512,6 +1537,16 @@ void MIDIDevice::FluidSettingStr(const char *setting, const char *value)
{
}
//==========================================================================
//
// MIDIDevice :: WildMidiSetOption
//
//==========================================================================
void MIDIDevice::WildMidiSetOption(int opt, int set)
{
}
//==========================================================================
//
// MIDIDevice :: GetStats

View file

@ -322,7 +322,12 @@ DWORD *MIDISong2::MakeEvents(DWORD *events, DWORD *max_event_p, DWORD max_time)
// Play all events for this tick.
do
{
DWORD *new_events = SendCommand(events, TrackDue, time);
bool sysex_noroom = false;
DWORD *new_events = SendCommand(events, TrackDue, time, max_event_p - events, sysex_noroom);
if (sysex_noroom)
{
return events;
}
TrackDue = FindNextDue();
if (new_events != events)
{
@ -366,12 +371,15 @@ void MIDISong2::AdvanceTracks(DWORD time)
//
//==========================================================================
DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay)
DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay, ptrdiff_t room, bool &sysex_noroom)
{
DWORD len;
BYTE event, data1 = 0, data2 = 0;
int i;
sysex_noroom = false;
size_t start_p = track->TrackP;
CHECK_FINISHED
event = track->TrackBegin[track->TrackP++];
CHECK_FINISHED
@ -588,13 +596,44 @@ DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay)
}
else
{
// Skip SysEx events just because I don't want to bother with them.
// The old MIDI player ignored them too, so this won't break
// anything that played before.
// SysEx events could potentially not have enough room in the buffer...
if (event == MIDI_SYSEX || event == MIDI_SYSEXEND)
{
len = track->ReadVarLen ();
track->TrackP += len;
len = track->ReadVarLen();
if (len >= (MAX_EVENTS-1)*3*4)
{ // This message will never fit. Throw it away.
track->TrackP += len;
}
else if (len + 12 >= (size_t)room * 4)
{ // Not enough room left in this buffer. Backup and wait for the next one.
track->TrackP = start_p;
sysex_noroom = true;
return events;
}
else
{
events[0] = delay;
events[1] = 0;
BYTE *msg = (BYTE *)&events[3];
if (event == MIDI_SYSEX)
{ // Need to add the SysEx marker to the message.
events[2] = (MEVT_LONGMSG << 24) | (len + 1);
*msg++ = MIDI_SYSEX;
}
else
{
events[2] = (MEVT_LONGMSG << 24) | len;
}
memcpy(msg, &track->TrackBegin[track->TrackP], len);
msg += len;
// Must pad with 0
while ((size_t)msg & 3)
{
*msg++ = 0;
}
events = (DWORD *)msg;
track->TrackP += len;
}
}
else if (event == MIDI_META)
{

View file

@ -0,0 +1,232 @@
/*
** music_wildmidi_mididevice.cpp
** Provides access to WildMidi as a generic MIDI device.
**
**---------------------------------------------------------------------------
** Copyright 2015 Randy Heit
** All rights reserved.
**
** 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.
**---------------------------------------------------------------------------
**
*/
// HEADER FILES ------------------------------------------------------------
#include "i_musicinterns.h"
#include "templates.h"
#include "doomdef.h"
#include "m_swap.h"
#include "w_wad.h"
#include "v_text.h"
// MACROS ------------------------------------------------------------------
// TYPES -------------------------------------------------------------------
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
// PRIVATE DATA DEFINITIONS ------------------------------------------------
static FString CurrentConfig;
// PUBLIC DATA DEFINITIONS -------------------------------------------------
CVAR(String, wildmidi_config, "", CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CVAR(Int, wildmidi_frequency, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Bool, wildmidi_reverb, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
if (currSong != NULL)
currSong->WildMidiSetOption(WM_MO_REVERB, *self? WM_MO_REVERB:0);
}
CUSTOM_CVAR(Bool, wildmidi_enhanced_resampling, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{
if (currSong != NULL)
currSong->WildMidiSetOption(WM_MO_ENHANCED_RESAMPLING, *self? WM_MO_ENHANCED_RESAMPLING:0);
}
// CODE --------------------------------------------------------------------
//==========================================================================
//
// WildMIDIDevice Constructor
//
//==========================================================================
WildMIDIDevice::WildMIDIDevice()
{
Renderer = NULL;
if (wildmidi_frequency >= 11025 && wildmidi_frequency < 65536)
{ // Use our own sample rate instead of the global one
SampleRate = wildmidi_frequency;
}
else
{ // Else make sure we're not outside of WildMidi's range
SampleRate = clamp(SampleRate, 11025, 65535);
}
if (CurrentConfig.CompareNoCase(wildmidi_config) != 0 || SampleRate != WildMidi_GetSampleRate())
{
if (CurrentConfig.IsNotEmpty())
{
WildMidi_Shutdown();
CurrentConfig = "";
}
if (!WildMidi_Init(wildmidi_config, SampleRate, 0))
{
CurrentConfig = wildmidi_config;
}
}
if (CurrentConfig.IsNotEmpty())
{
Renderer = new WildMidi_Renderer();
int flags = 0;
if (wildmidi_enhanced_resampling) flags |= WM_MO_ENHANCED_RESAMPLING;
if (wildmidi_reverb) flags |= WM_MO_REVERB;
Renderer->SetOption(WM_MO_ENHANCED_RESAMPLING | WM_MO_REVERB, flags);
}
}
//==========================================================================
//
// WildMIDIDevice Destructor
//
//==========================================================================
WildMIDIDevice::~WildMIDIDevice()
{
Close();
if (Renderer != NULL)
{
delete Renderer;
}
// Do not shut down the device so that it can be reused for the next song being played.
}
//==========================================================================
//
// WildMIDIDevice :: Open
//
// Returns 0 on success.
//
//==========================================================================
int WildMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata)
{
if (Renderer == NULL)
{
return 1;
}
int ret = OpenStream(2, 0, callback, userdata);
if (ret == 0)
{
// Renderer->Reset();
}
return ret;
}
//==========================================================================
//
// WildMIDIDevice :: PrecacheInstruments
//
// Each entry is packed as follows:
// Bits 0- 6: Instrument number
// Bits 7-13: Bank number
// Bit 14: Select drum set if 1, tone bank if 0
//
//==========================================================================
void WildMIDIDevice::PrecacheInstruments(const WORD *instruments, int count)
{
for (int i = 0; i < count; ++i)
{
Renderer->LoadInstrument((instruments[i] >> 7) & 127, instruments[i] >> 14, instruments[i] & 127);
}
}
//==========================================================================
//
// WildMIDIDevice :: HandleEvent
//
//==========================================================================
void WildMIDIDevice::HandleEvent(int status, int parm1, int parm2)
{
Renderer->ShortEvent(status, parm1, parm2);
}
//==========================================================================
//
// WildMIDIDevice :: HandleLongEvent
//
//==========================================================================
void WildMIDIDevice::HandleLongEvent(const BYTE *data, int len)
{
Renderer->LongEvent(data, len);
}
//==========================================================================
//
// WildMIDIDevice :: ComputeOutput
//
//==========================================================================
void WildMIDIDevice::ComputeOutput(float *buffer, int len)
{
Renderer->ComputeOutput(buffer, len);
}
//==========================================================================
//
// WildMIDIDevice :: GetStats
//
//==========================================================================
FString WildMIDIDevice::GetStats()
{
FString out;
out.Format("%3d voices", Renderer->GetVoiceCount());
return out;
}
//==========================================================================
//
// WildMIDIDevice :: GetStats
//
//==========================================================================
void WildMIDIDevice::WildMidiSetOption(int opt, int set)
{
Renderer->SetOption(opt, set);
}

View file

@ -1239,7 +1239,7 @@ void FTextureManager::PrecacheLevel (void)
if (demoplayback)
return;
precacheTime = I_MSTime();
precacheTime = I_FPSTime();
hitlist = new BYTE[cnt];
memset (hitlist, 0, cnt);

View file

@ -35,82 +35,6 @@
namespace Timidity
{
static TArray<FString> PathList;
FString BuildPath(FString base, const char *name)
{
FString current;
if (base.IsNotEmpty())
{
current = base;
if (current[current.Len() - 1] != '/') current += '/';
}
current += name;
return current;
}
/* This is meant to find and open files for reading. */
FileReader *open_filereader(const char *name, int open, int *plumpnum)
{
FileReader *fp;
FString current_filename;
if (!name || !(*name))
{
return 0;
}
/* First try the given name */
current_filename = name;
FixPathSeperator(current_filename);
int lumpnum = Wads.CheckNumForFullName(current_filename);
if (open != OM_FILE)
{
if (lumpnum >= 0)
{
fp = Wads.ReopenLumpNum(lumpnum);
if (plumpnum) *plumpnum = lumpnum;
return fp;
}
if (open == OM_LUMP) // search the path list when not loading the main config
{
for (unsigned int plp = PathList.Size(); plp-- != 0; )
{ /* Try along the path then */
current_filename = BuildPath(PathList[plp], name);
lumpnum = Wads.CheckNumForFullName(current_filename);
if (lumpnum >= 0)
{
fp = Wads.ReopenLumpNum(lumpnum);
if (plumpnum) *plumpnum = lumpnum;
return fp;
}
}
return NULL;
}
}
if (plumpnum) *plumpnum = -1;
fp = new FileReader;
if (fp->Open(current_filename)) return fp;
if (name[0] != '/')
{
for (unsigned int plp = PathList.Size(); plp-- != 0; )
{ /* Try along the path then */
current_filename = BuildPath(PathList[plp], name);
if (fp->Open(current_filename)) return fp;
}
}
delete fp;
/* Nothing could be opened. */
current_filename = "";
return NULL;
}
/* This'll allocate memory or die. */
@ -132,17 +56,5 @@ void *safe_malloc(size_t count)
return 0; // Unreachable.
}
/* This adds a directory to the path list */
void add_to_pathlist(const char *s)
{
FString copy = s;
FixPathSeperator(copy);
PathList.Push(copy);
}
void clear_pathlist()
{
PathList.Clear();
}
}

View file

@ -142,7 +142,7 @@ static void reverse_data(sample_t *sp, int ls, int le)
TODO: do reverse loops right */
static Instrument *load_instrument(Renderer *song, const char *name, int percussion,
int panning, int amp, int note_to_use,
int panning, int note_to_use,
int strip_loop, int strip_envelope,
int strip_tail)
{
@ -159,16 +159,16 @@ static Instrument *load_instrument(Renderer *song, const char *name, int percuss
if (!name) return 0;
/* Open patch file */
if ((fp = open_filereader(name, openmode, NULL)) == NULL)
if ((fp = pathExpander.openFileReader(name, NULL)) == NULL)
{
/* Try with various extensions */
FString tmp = name;
tmp += ".pat";
if ((fp = open_filereader(tmp, openmode, NULL)) == NULL)
if ((fp = pathExpander.openFileReader(tmp, NULL)) == NULL)
{
#ifdef __unix__ // Windows isn't case-sensitive.
tmp.ToUpper();
if ((fp = open_filereader(tmp, openmode, NULL)) == NULL)
if ((fp = pathExpander.openFileReader(tmp, NULL)) == NULL)
#endif
{
noluck = true;
@ -372,7 +372,6 @@ fail:
{
sp->modes &= ~(PATCH_SUSTAIN | PATCH_LOOPEN | PATCH_BIDIR | PATCH_BACKWARD);
}
sp->modes |= PATCH_T_NO_LOOP;
}
if (strip_envelope == 1)
@ -398,37 +397,6 @@ fail:
patch_data.EnvelopeOffset[k] = patch_data.EnvelopeOffset[0];
}
}
sp->modes |= PATCH_T_NO_ENVELOPE;
}
else if (strip_envelope != 0)
{
/* Have to make a guess. */
if (!(sp->modes & (PATCH_LOOPEN | PATCH_BIDIR | PATCH_BACKWARD)))
{
/* No loop? Then what's there to sustain? No envelope needed either... */
sp->modes |= PATCH_T_NO_ENVELOPE;
cmsg(CMSG_INFO, VERB_DEBUG, " - No loop, removing sustain and envelope\n");
}
else if (memcmp(patch_data.EnvelopeRate, "??????", 6) == 0 || patch_data.EnvelopeOffset[GF1_RELEASEC] >= 100)
{
/* Envelope rates all maxed out? Envelope end at a high "offset"?
That's a weird envelope. Take it out. */
sp->modes |= PATCH_T_NO_ENVELOPE;
cmsg(CMSG_INFO, VERB_DEBUG, " - Weirdness, removing envelope\n");
}
else if (!(sp->modes & PATCH_SUSTAIN))
{
/* No sustain? Then no envelope. I don't know if this is
justified, but patches without sustain usually don't need the
envelope either... at least the Gravis ones. They're mostly
drums. I think. */
sp->modes |= PATCH_T_NO_ENVELOPE;
cmsg(CMSG_INFO, VERB_DEBUG, " - No sustain, removing envelope\n");
}
}
if (!(sp->modes & PATCH_NO_SRELEASE))
{ // TiMidity thinks that this is an envelope enable flag.
sp->modes |= PATCH_T_NO_ENVELOPE;
}
for (j = 0; j < 6; j++)
@ -470,29 +438,6 @@ fail:
sp->modes |= PATCH_LOOPEN; /* just in case */
}
if (amp != -1)
{
sp->volume = (amp) / 100.f;
}
else
{
/* Try to determine a volume scaling factor for the sample.
This is a very crude adjustment, but things sound more
balanced with it. Still, this should be a runtime option.
(This is ignored unless midi_timiditylike is turned on.) */
int i;
sample_t maxamp = 0, a;
sample_t *tmp;
for (i = sp->data_length, tmp = sp->data; i; --i)
{
a = fabsf(*tmp++);
if (a > maxamp)
maxamp = a;
}
sp->volume = 1 / maxamp;
cmsg(CMSG_INFO, VERB_DEBUG, " * volume comp: %f\n", sp->volume);
}
/* Then fractional samples */
sp->data_length <<= FRACTION_BITS;
sp->loop_start <<= FRACTION_BITS;
@ -653,7 +598,6 @@ static int fill_bank(Renderer *song, int dr, int b)
ip = load_instrument(song, bank->tone[i].name,
(dr) ? 1 : 0,
bank->tone[i].pan,
bank->tone[i].amp,
(bank->tone[i].note != -1) ? bank->tone[i].note : ((dr) ? i : -1),
(bank->tone[i].strip_loop != -1) ? bank->tone[i].strip_loop : ((dr) ? 1 : -1),
(bank->tone[i].strip_envelope != -1) ? bank->tone[i].strip_envelope : ((dr) ? 1 : -1),
@ -731,7 +675,7 @@ void free_instruments()
int Renderer::set_default_instrument(const char *name)
{
Instrument *ip;
if ((ip = load_instrument(this, name, 0, -1, -1, -1, 0, 0, 0)) == NULL)
if ((ip = load_instrument(this, name, 0, -1, -1, 0, 0, 0)) == NULL)
{
return -1;
}

View file

@ -1141,7 +1141,6 @@ static void load_region_dls(Renderer *song, Sample *sample, DLS_Instrument *ins,
sample->loop_start = rgn->wsmp_loop->ulStart / 2;
sample->loop_end = sample->loop_start + (rgn->wsmp_loop->ulLength / 2);
}
sample->volume = 1.0f;
if (sample->modes & PATCH_SUSTAIN)
{

View file

@ -54,7 +54,7 @@ void font_add(const char *filename, int load_order)
}
else
{
FileReader *fp = open_filereader(filename, openmode, NULL);
FileReader *fp = pathExpander.openFileReader(filename, NULL);
if (fp != NULL)
{

View file

@ -1441,7 +1441,6 @@ void SFFile::ApplyGeneratorsToRegion(SFGenComposite *gen, SFSample *sfsamp, Rend
sp->root_freq = note_to_freq(sp->scale_note);
sp->sample_rate = sfsamp->SampleRate;
sp->key_group = gen->exclusiveClass;
sp->volume = 1;
// Set key scaling
if (gen->keynum >= 0 && gen->keynum <= 127)
@ -1502,7 +1501,7 @@ void SFFile::ApplyGeneratorsToRegion(SFGenComposite *gen, SFSample *sfsamp, Rend
void SFFile::LoadSample(SFSample *sample)
{
FileReader *fp = open_filereader(Filename, openmode, NULL);
FileReader *fp = pathExpander.openFileReader(Filename, NULL);
DWORD i;
if (fp == NULL)

View file

@ -29,8 +29,6 @@
#include "templates.h"
#include "c_cvars.h"
EXTERN_CVAR(Bool, midi_timiditylike)
namespace Timidity
{
@ -78,16 +76,7 @@ void GF1Envelope::Init(Renderer *song, Voice *v)
void GF1Envelope::Release(Voice *v)
{
if (midi_timiditylike)
{
if (!(v->sample->modes & PATCH_T_NO_ENVELOPE))
{
stage = GF1_RELEASE;
Recompute(v);
}
// else ... loop was already turned off by the caller
}
else if (!(v->sample->modes & PATCH_NO_SRELEASE) || (v->sample->modes & PATCH_FAST_REL))
if (!(v->sample->modes & PATCH_NO_SRELEASE) || (v->sample->modes & PATCH_FAST_REL))
{
/* ramp out to minimum volume with rate from final release stage */
stage = GF1_RELEASEC+1;
@ -119,23 +108,11 @@ bool GF1Envelope::Recompute(Voice *v)
bUpdating = false;
v->status &= ~(VOICE_SUSTAINING | VOICE_LPE);
v->status |= VOICE_RELEASING;
if (midi_timiditylike)
{ /* kill the voice ... or not */
if (volume <= 0)
{
v->status |= VOICE_STOPPING;
}
return 1;
}
else
{ /* play sampled release */
}
/* play sampled release */
return 0;
}
if (newstage == GF1_RELEASE && !(v->status & VOICE_RELEASING) &&
((!midi_timiditylike && (v->sample->modes & PATCH_SUSTAIN)) ||
(midi_timiditylike && !(v->sample->modes & PATCH_T_NO_ENVELOPE))))
if (newstage == GF1_RELEASE && !(v->status & VOICE_RELEASING) && (v->sample->modes & PATCH_SUSTAIN))
{
v->status |= VOICE_SUSTAINING;
/* Freeze envelope until note turns off. Trumpets want this. */
@ -161,10 +138,6 @@ bool GF1Envelope::Recompute(Voice *v)
bool GF1Envelope::Update(Voice *v)
{
if (midi_timiditylike && (v->sample->modes & PATCH_T_NO_ENVELOPE))
{
return 0;
}
volume += increment;
if (((increment < 0) && (volume <= target)) || ((increment > 0) && (volume >= target)))
{
@ -182,36 +155,14 @@ void GF1Envelope::ApplyToAmp(Voice *v)
double env_vol = v->attenuation;
double final_amp;
if (midi_timiditylike)
{
final_amp = v->sample->volume * FINAL_MIX_TIMIDITY_SCALE;
if (v->tremolo_phase_increment != 0)
{
env_vol *= v->tremolo_volume;
}
if (!(v->sample->modes & PATCH_T_NO_ENVELOPE))
{
if (stage > GF1_ATTACK)
{
env_vol *= pow(2.0, volume * (6.0 / (1 << 30)) - 6.0);
}
else
{
env_vol *= volume / float(1 << 30);
}
}
}
else
{
final_amp = FINAL_MIX_SCALE;
if (v->tremolo_phase_increment != 0)
{ // [RH] FIXME: This is wrong. Tremolo should offset the
// envelope volume, not scale it.
env_vol *= v->tremolo_volume;
}
env_vol *= volume / float(1 << 30);
env_vol = calc_gf1_amp(env_vol);
final_amp = FINAL_MIX_SCALE;
if (v->tremolo_phase_increment != 0)
{ // [RH] FIXME: This is wrong. Tremolo should offset the
// envelope volume, not scale it.
env_vol *= v->tremolo_volume;
}
env_vol *= volume / float(1 << 30);
env_vol = calc_gf1_amp(env_vol);
env_vol *= final_amp;
v->left_mix = float(env_vol * v->left_offset);
v->right_mix = float(env_vol * v->right_offset);

View file

@ -29,8 +29,6 @@
#include "timidity.h"
#include "c_cvars.h"
EXTERN_CVAR(Bool, midi_timiditylike)
namespace Timidity
{
@ -118,7 +116,7 @@ void Renderer::recompute_freq(int v)
voice[v].sample_increment = (int)(a);
}
static BYTE vol_table[] = {
static const BYTE vol_table[] = {
000 /* 000 */, 129 /* 001 */, 145 /* 002 */, 155 /* 003 */,
161 /* 004 */, 166 /* 005 */, 171 /* 006 */, 174 /* 007 */,
177 /* 008 */, 180 /* 009 */, 182 /* 010 */, 185 /* 011 */,
@ -161,16 +159,7 @@ void Renderer::recompute_amp(Voice *v)
if (v->sample->type == INST_GUS)
{
if (midi_timiditylike)
{
v->attenuation = float(timidityxx_perceived_vol(v->velocity / 127.0) *
timidityxx_perceived_vol(chanvol / 127.0) *
timidityxx_perceived_vol(chanexpr / 127.0));
}
else
{
v->attenuation = (vol_table[(chanvol * chanexpr) / 127] * vol_table[v->velocity]) * ((127 + 64) / 12419775.f);
}
v->attenuation = (vol_table[(chanvol * chanexpr) / 127] * vol_table[v->velocity]) * ((127 + 64) / 12419775.f);
}
else
{
@ -199,7 +188,7 @@ void Renderer::compute_pan(double pan, int type, float &left_offset, float &righ
}
else
{
if (type == INST_GUS && !midi_timiditylike)
if (type == INST_GUS)
{
/* Original amp equation looks like this:
* calc_gf1_amp(atten + offset)
@ -218,9 +207,7 @@ void Renderer::compute_pan(double pan, int type, float &left_offset, float &righ
}
else
{
/* I have no idea what equation, if any, will reproduce the sc_pan_table
* that TiMidity++ uses, so midi_timiditylike gets the same Equal Power
* Panning as SF2/DLS.
/* Equal Power Panning for SF2/DLS.
*/
left_offset = (float)sqrt(1 - pan);
right_offset = (float)sqrt(pan);
@ -561,7 +548,7 @@ void Renderer::finish_note(int i)
v->status &= ~VOICE_SUSTAINING;
v->status |= VOICE_RELEASING;
if (!(v->sample->modes & PATCH_NO_SRELEASE) || midi_timiditylike)
if (!(v->sample->modes & PATCH_NO_SRELEASE))
{
v->status &= ~VOICE_LPE; /* sampled release */
}

View file

@ -28,8 +28,6 @@
#include "timidity.h"
#include "c_cvars.h"
EXTERN_CVAR(Bool, midi_timiditylike)
namespace Timidity
{
@ -522,7 +520,7 @@ sample_t *resample_voice(Renderer *song, Voice *vp, int *countptr)
if (vp->vibrato_control_ratio)
{
if (vp->status & VOICE_LPE && !(midi_timiditylike && vp->sample->modes & PATCH_T_NO_LOOP))
if (vp->status & VOICE_LPE)
{
if (modes & PATCH_BIDIR)
return rs_vib_bidir(song->resample_buffer, song->rate, vp, *countptr);
@ -536,7 +534,7 @@ sample_t *resample_voice(Renderer *song, Voice *vp, int *countptr)
}
else
{
if (vp->status & VOICE_LPE && !(midi_timiditylike && vp->sample->modes & PATCH_T_NO_LOOP))
if (vp->status & VOICE_LPE)
{
if (modes & PATCH_BIDIR)
return rs_bidir(song->resample_buffer, vp, *countptr);

View file

@ -34,7 +34,6 @@
CVAR(String, midi_config, CONFIG_FILE, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR(Int, midi_voices, 32, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR(Bool, midi_timiditylike, false, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR(String, gus_patchdir, "", CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR(Bool, midi_dmxgus, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR(Int, gus_memsize, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
@ -42,10 +41,10 @@ CVAR(Int, gus_memsize, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
namespace Timidity
{
PathExpander pathExpander;
ToneBank *tonebank[MAXBANK], *drumset[MAXBANK];
static FString def_instr_name;
int openmode = OM_FILEORLUMP;
static int read_config_file(const char *name, bool ismain)
{
@ -62,21 +61,21 @@ static int read_config_file(const char *name, bool ismain)
return (-1);
}
if (ismain) openmode = OM_FILEORLUMP;
if (ismain) pathExpander.openmode = PathExpander::OM_FILEORLUMP;
if (!(fp = open_filereader(name, openmode, &lumpnum)))
if (!(fp = pathExpander.openFileReader(name, &lumpnum)))
return -1;
if (ismain)
{
if (lumpnum > 0)
{
openmode = OM_LUMP;
clear_pathlist(); // when reading from a PK3 we won't want to use any external path
pathExpander.openmode = PathExpander::OM_LUMP;
pathExpander.clearPathlist(); // when reading from a PK3 we don't want to use any external path
}
else
{
openmode = OM_FILE;
pathExpander.openmode = PathExpander::OM_FILE;
}
}
@ -288,7 +287,7 @@ static int read_config_file(const char *name, bool ismain)
return -2;
}
for (i = 1; i < words; i++)
add_to_pathlist(w[i]);
pathExpander.addToPathlist(w[i]);
}
else if (!strcmp(w[0], "source"))
{
@ -377,7 +376,7 @@ static int read_config_file(const char *name, bool ismain)
delete fp;
return -2;
}
bank->tone[i].note = bank->tone[i].amp = bank->tone[i].pan =
bank->tone[i].note = bank->tone[i].pan =
bank->tone[i].fontbank = bank->tone[i].fontpreset =
bank->tone[i].fontnote = bank->tone[i].strip_loop =
bank->tone[i].strip_envelope = bank->tone[i].strip_tail = -1;
@ -415,14 +414,7 @@ static int read_config_file(const char *name, bool ismain)
*cp++ = 0;
if (!strcmp(w[j], "amp"))
{
k = atoi(cp);
if ((k < 0 || k > MAX_AMPLIFICATION) || (*cp < '0' || *cp > '9'))
{
Printf("%s: line %d: amplification must be between 0 and %d\n", name, line, MAX_AMPLIFICATION);
delete fp;
return -2;
}
bank->tone[i].amp = k;
/* Ignored */
}
else if (!strcmp(w[j], "note"))
{
@ -532,15 +524,15 @@ int LoadConfig(const char *filename)
* file itself since that file should contain any other directory
* that needs to be added to the search path.
*/
clear_pathlist();
pathExpander.clearPathlist();
#ifdef _WIN32
add_to_pathlist("C:\\TIMIDITY");
add_to_pathlist("\\TIMIDITY");
add_to_pathlist(progdir);
pathExpander.addToPathlist("C:\\TIMIDITY");
pathExpander.addToPathlist("\\TIMIDITY");
pathExpander.addToPathlist(progdir);
#else
add_to_pathlist("/usr/local/lib/timidity");
add_to_pathlist("/etc/timidity");
add_to_pathlist("/etc");
pathExpander.addToPathlist("/usr/local/lib/timidity");
pathExpander.addToPathlist("/etc/timidity");
pathExpander.addToPathlist("/etc");
#endif
/* Some functions get aggravated if not even the standard banks are available. */
@ -579,10 +571,10 @@ int LoadDMXGUS()
if (ultradir.IsNotEmpty())
{
ultradir += "/midi";
add_to_pathlist(ultradir.GetChars());
pathExpander.addToPathlist(ultradir.GetChars());
}
// Load DMXGUS lump and patches from gus_patchdir
add_to_pathlist(gus_patchdir);
pathExpander.addToPathlist(gus_patchdir);
char readbuffer[1024];
long size = data.GetLength();
@ -676,7 +668,7 @@ int LoadDMXGUS()
continue;
int val = k % 128;
bank->tone[val].note = bank->tone[val].amp = bank->tone[val].pan =
bank->tone[val].note = bank->tone[val].pan =
bank->tone[val].fontbank = bank->tone[val].fontpreset =
bank->tone[val].fontnote = bank->tone[val].strip_loop =
bank->tone[val].strip_envelope = bank->tone[val].strip_tail = -1;

View file

@ -21,6 +21,7 @@
#define TIMIDITY_H
#include "doomtype.h"
#include "pathexpander.h"
class FileReader;
@ -54,10 +55,6 @@ config.h
volume level of FMOD's built-in MIDI player. */
#define FINAL_MIX_SCALE 0.5
/* This value is used instead when midi_timiditylike is turned on,
because TiMidity++ is louder than a GUS. */
#define FINAL_MIX_TIMIDITY_SCALE 0.3
/* How many bits to use for the fractional part of sample positions.
This affects tonal accuracy. The entire position counter must fit
in 32 bits, so with FRACTION_BITS equal to 12, the maximum size of
@ -172,17 +169,8 @@ extern __inline__ double pow_x87_inline(double x,double y)
common.h
*/
#define OM_FILEORLUMP 0
#define OM_LUMP 1
#define OM_FILE 2
extern void add_to_pathlist(const char *s);
extern void clear_pathlist();
extern void *safe_malloc(size_t count);
FileReader *open_filereader(const char *name, int open, int *plumpnum);
extern int openmode;
/*
controls.h
*/
@ -219,9 +207,6 @@ enum
PATCH_SUSTAIN = (1<<5),
PATCH_NO_SRELEASE = (1<<6),
PATCH_FAST_REL = (1<<7),
PATCH_T_NO_ENVELOPE = (1<<8),
PATCH_T_NO_LOOP = (1<<9)
};
struct Sample
@ -247,8 +232,6 @@ struct Sample
short release_vol;
} sf2;
} envelope;
float
volume;
sample_t *data;
SDWORD
tremolo_sweep_increment, tremolo_phase_increment,
@ -324,11 +307,12 @@ struct Instrument
struct ToneBankElement
{
ToneBankElement() :
note(0), amp(0), pan(0), strip_loop(0), strip_envelope(0), strip_tail(0)
note(0), pan(0), strip_loop(0), strip_envelope(0), strip_tail(0)
{}
FString name;
int note, amp, pan, fontbank, fontpreset, fontnote, strip_loop, strip_envelope, strip_tail;
int note, pan, fontbank, fontpreset, fontnote;
SBYTE strip_loop, strip_envelope, strip_tail;
};
/* A hack to delay instrument loading until after reading the entire MIDI file. */
@ -616,8 +600,6 @@ const double log_of_2 = 0.69314718055994529;
#define calc_gf1_amp(x) (pow(2.0,((x)*16.0 - 16.0))) // Actual GUS equation
#define cb_to_amp(x) (pow(10.0, (x) * (1 / -200.0))) // centibels to amp
#define db_to_amp(x) (pow(10.0, (x) * (1 / -20.0))) // decibels to map
#define timidityxx_perceived_vol(x) (pow((x), 1.66096404744))
/*
timidity.h
@ -627,6 +609,7 @@ int LoadConfig(const char *filename);
int LoadDMXGUS();
extern int LoadConfig();
extern void FreeAll();
extern PathExpander pathExpander;
extern ToneBank *tonebank[MAXBANK];
extern ToneBank *drumset[MAXBANK];

View file

@ -76,7 +76,7 @@ const char *GetVersionString();
// Use 4500 as the base git save version, since it's higher than the
// SVN revision ever got.
#define SAVEVER 4525
#define SAVEVER 4526
#define SAVEVERSTRINGIFY2(x) #x
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)

View file

@ -184,6 +184,7 @@ void FWadCollection::InitMultipleFiles (TArray<FString> &filenames)
}
RenameNerve();
RenameSprites();
FixMacHexen();
// [RH] Set up hash table
FirstLumpIndex = new DWORD[NumLumps];
@ -956,6 +957,41 @@ void FWadCollection::RenameNerve ()
}
}
//==========================================================================
//
// FixMacHexen
//
// Rename unused high resolution font lumps because they are incorrectly
// treated as extended characters
//
//==========================================================================
void FWadCollection::FixMacHexen()
{
if (GAME_Hexen != gameinfo.gametype)
{
return;
}
for (int i = GetFirstLump(IWAD_FILENUM), last = GetLastLump(IWAD_FILENUM); i <= last; ++i)
{
assert(IWAD_FILENUM == LumpInfo[i].wadnum);
FResourceLump* const lump = LumpInfo[i].lump;
char* const name = lump->Name;
// Unwanted lumps are named like FONTA??1
if (8 == strlen(name)
&& MAKE_ID('F', 'O', 'N', 'T') == lump->dwName
&& 'A' == name[4] && '1' == name[7]
&& isdigit(name[5]) && isdigit(name[6]))
{
name[0] = '\0';
}
}
}
//==========================================================================
//
// W_FindLump

View file

@ -238,6 +238,7 @@ protected:
private:
void RenameSprites();
void RenameNerve();
void FixMacHexen();
void DeleteAll();
};

94
src/wildmidi/common.h Normal file
View file

@ -0,0 +1,94 @@
/*
common.h
Midi Wavetable Processing library
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef __COMMON_H
#define __COMMON_H
#define SAMPLE_16BIT 0x01
#define SAMPLE_UNSIGNED 0x02
#define SAMPLE_LOOP 0x04
#define SAMPLE_PINGPONG 0x08
#define SAMPLE_REVERSE 0x10
#define SAMPLE_SUSTAIN 0x20
#define SAMPLE_ENVELOPE 0x40
#define SAMPLE_CLAMPED 0x80
#ifdef DEBUG_SAMPLES
#define SAMPLE_CONVERT_DEBUG(dx) printf("\r%s\n",dx)
#else
#define SAMPLE_CONVERT_DEBUG(dx)
#endif
extern unsigned short int _WM_SampleRate;
struct _sample {
unsigned long int data_length;
unsigned long int loop_start;
unsigned long int loop_end;
unsigned long int loop_size;
unsigned char loop_fraction;
unsigned short int rate;
unsigned long int freq_low;
unsigned long int freq_high;
unsigned long int freq_root;
unsigned char modes;
signed long int env_rate[7];
signed long int env_target[7];
unsigned long int inc_div;
signed short *data;
struct _sample *next;
};
struct _env {
float time;
float level;
unsigned char set;
};
struct _patch {
unsigned short patchid;
unsigned char loaded;
char *filename;
signed short int amp;
unsigned char keep;
unsigned char remove;
struct _env env[6];
unsigned char note;
unsigned long int inuse_count;
struct _sample *first_sample;
struct _patch *next;
};
/* Set our global defines here */
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
#ifndef M_LN2
#define M_LN2 0.69314718055994530942
#endif
#endif /* __COMMON_H */

112
src/wildmidi/file_io.cpp Normal file
View file

@ -0,0 +1,112 @@
/*
** file_io.cpp
** ZDoom compatible file IO interface for WildMIDI
** (This file was completely redone to remove the low level IO code references)
**
**---------------------------------------------------------------------------
** Copyright 2010 Christoph Oelckers
** All rights reserved.
**
** 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.
**---------------------------------------------------------------------------
**
*/
#include <errno.h>
#include "../files.h"
#include "wm_error.h"
#include "file_io.h"
#include "pathexpander.h"
#include "cmdlib.h"
static PathExpander wmPathExpander;
unsigned char *_WM_BufferFile(const char *filename, unsigned long int *size, bool ismain)
{
FileReader *fp;
int lumpnum;
if (ismain)
{
wmPathExpander.openmode = PathExpander::OM_FILEORLUMP;
wmPathExpander.clearPathlist();
#ifdef _WIN32
wmPathExpander.addToPathlist("C:\\TIMIDITY");
wmPathExpander.addToPathlist("\\TIMIDITY");
wmPathExpander.addToPathlist(progdir);
#else
wmPathExpander.addToPathlist("/usr/local/lib/timidity");
wmPathExpander.addToPathlist("/etc/timidity");
wmPathExpander.addToPathlist("/etc");
#endif
}
if (!(fp = wmPathExpander.openFileReader(filename, &lumpnum)))
return NULL;
if (ismain)
{
if (lumpnum > 0)
{
wmPathExpander.openmode = PathExpander::OM_LUMP;
wmPathExpander.clearPathlist(); // when reading from a PK3 we don't want to use any external path
}
else
{
wmPathExpander.openmode = PathExpander::OM_FILE;
}
}
if (fp == NULL)
{
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, errno);
return NULL;
}
long fsize = fp->GetLength();
if (fsize > WM_MAXFILESIZE)
{
/* don't bother loading suspiciously long files */
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LONGFIL, filename, 0);
return NULL;
}
unsigned char *data = (unsigned char*)malloc(fsize+1);
if (data == NULL)
{
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, errno);
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, errno);
return NULL;
}
fp->Read(data, fsize);
delete fp;
data[fsize] = 0;
*size = fsize;
return data;
}

33
src/wildmidi/file_io.h Normal file
View file

@ -0,0 +1,33 @@
/*
file_io.c
file handling
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef __FILE_IO_H
#define __FILE_IO_H
#define WM_MAXFILESIZE 0x1fffffff
extern unsigned char *_WM_BufferFile (const char *filename, unsigned long int *size, bool mainfile = false);
#endif /* __FILE_IO_H */

900
src/wildmidi/gus_pat.cpp Normal file
View file

@ -0,0 +1,900 @@
/*
gus_pat.c
Midi Wavetable Processing library
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
//#include "config.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gus_pat.h"
#include "common.h"
#include "wm_error.h"
#include "file_io.h"
#ifdef DEBUG_GUSPAT
#define GUSPAT_FILENAME_DEBUG(dx) fprintf(stderr,"\r%s\n",dx)
#define GUSPAT_INT_DEBUG(dx,dy) fprintf(stderr,"\r%s: %i\n",dx,dy)
#define GUSPAT_FLOAT_DEBUG(dx,dy) fprintf(stderr,"\r%s: %f\n",dx,dy)
#define GUSPAT_START_DEBUG() fprintf(stderr,"\r")
#define GUSPAT_MODE_DEBUG(dx,dy,dz) if (dx & dy) fprintf(stderr,"%s",dz)
#define GUSPAT_END_DEBUG() fprintf(stderr,"\n")
#else
#define GUSPAT_FILENAME_DEBUG(dx)
#define GUSPAT_INT_DEBUG(dx,dy)
#define GUSPAT_FLOAT_DEBUG(dx,dy)
#define GUSPAT_START_DEBUG()
#define GUSPAT_MODE_DEBUG(dx,dy,dz)
#define GUSPAT_END_DEBUG()
#endif
/*
* sample data conversion functions
* convert data to signed shorts
*/
/* 8bit signed */
static int convert_8s(unsigned char *data, struct _sample *gus_sample) {
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->data_length;
signed short int *write_data = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc((gus_sample->data_length + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data++ = (*read_data++) << 8;
} while (read_data != read_end);
return 0;
}
_WM_ERROR_NEW("(%s:%i) ERROR: calloc failed (%s)", __FUNCTION__, __LINE__,
strerror(errno));
return -1;
}
/* 8bit signed ping pong */
static int convert_8sp(unsigned char *data, struct _sample *gus_sample) {
unsigned long int loop_length = gus_sample->loop_end
- gus_sample->loop_start;
unsigned long int dloop_length = loop_length * 2;
unsigned long int new_length = gus_sample->data_length + dloop_length;
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->loop_start;
signed short int *write_data = NULL;
signed short int *write_data_a = NULL;
signed short int *write_data_b = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data++ = (*read_data++) << 8;
} while (read_data != read_end);
*write_data = (*read_data++ << 8);
write_data_a = write_data + dloop_length;
*write_data_a-- = *write_data;
write_data++;
write_data_b = write_data + dloop_length;
read_end = data + gus_sample->loop_end;
do {
*write_data = (*read_data++) << 8;
*write_data_a-- = *write_data;
*write_data_b++ = *write_data;
write_data++;
} while (read_data != read_end);
*write_data = (*read_data++ << 8);
*write_data_b++ = *write_data;
read_end = data + gus_sample->data_length;
if (read_data != read_end) {
do {
*write_data_b++ = (*read_data++) << 8;
} while (read_data != read_end);
}
gus_sample->loop_start += loop_length;
gus_sample->loop_end += dloop_length;
gus_sample->data_length = new_length;
gus_sample->modes ^= SAMPLE_PINGPONG;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 8bit signed reverse */
static int convert_8sr(unsigned char *data, struct _sample *gus_sample) {
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->data_length;
signed short int *write_data = NULL;
unsigned long int tmp_loop = 0;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc((gus_sample->data_length + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data + gus_sample->data_length - 1;
do {
*write_data-- = (*read_data++) << 8;
} while (read_data != read_end);
tmp_loop = gus_sample->loop_end;
gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start;
gus_sample->loop_start = gus_sample->data_length - tmp_loop;
gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4)
| ((gus_sample->loop_fraction & 0xf0) >> 4);
gus_sample->modes ^= SAMPLE_REVERSE;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 8bit signed reverse ping pong */
static int convert_8srp(unsigned char *data, struct _sample *gus_sample) {
unsigned long int loop_length = gus_sample->loop_end
- gus_sample->loop_start;
unsigned long int dloop_length = loop_length * 2;
unsigned long int new_length = gus_sample->data_length + dloop_length;
unsigned char *read_data = data + gus_sample->data_length - 1;
unsigned char *read_end = data + gus_sample->loop_end;
signed short int *write_data = NULL;
signed short int *write_data_a = NULL;
signed short int *write_data_b = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data++ = (*read_data--) << 8;
} while (read_data != read_end);
*write_data = (*read_data-- << 8);
write_data_a = write_data + dloop_length;
*write_data_a-- = *write_data;
write_data++;
write_data_b = write_data + dloop_length;
read_end = data + gus_sample->loop_start;
do {
*write_data = (*read_data--) << 8;
*write_data_a-- = *write_data;
*write_data_b++ = *write_data;
write_data++;
} while (read_data != read_end);
*write_data = (*read_data-- << 8);
*write_data_b++ = *write_data;
read_end = data - 1;
do {
*write_data_b++ = (*read_data--) << 8;
write_data_b++;
} while (read_data != read_end);
gus_sample->loop_start += loop_length;
gus_sample->loop_end += dloop_length;
gus_sample->data_length = new_length;
gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 8bit unsigned */
static int convert_8u(unsigned char *data, struct _sample *gus_sample) {
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->data_length;
signed short int *write_data = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc((gus_sample->data_length + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data++ = ((*read_data++) ^ 0x80) << 8;
} while (read_data != read_end);
gus_sample->modes ^= SAMPLE_UNSIGNED;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 8bit unsigned ping pong */
static int convert_8up(unsigned char *data, struct _sample *gus_sample) {
unsigned long int loop_length = gus_sample->loop_end
- gus_sample->loop_start;
unsigned long int dloop_length = loop_length * 2;
unsigned long int new_length = gus_sample->data_length + dloop_length;
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->loop_start;
signed short int *write_data = NULL;
signed short int *write_data_a = NULL;
signed short int *write_data_b = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data++ = ((*read_data++) ^ 0x80) << 8;
} while (read_data != read_end);
*write_data = ((*read_data++) ^ 0x80) << 8;
write_data_a = write_data + dloop_length;
*write_data_a-- = *write_data;
write_data++;
write_data_b = write_data + dloop_length;
read_end = data + gus_sample->loop_end;
do {
*write_data = ((*read_data++) ^ 0x80) << 8;
*write_data_a-- = *write_data;
*write_data_b++ = *write_data;
write_data++;
} while (read_data != read_end);
*write_data = ((*read_data++) ^ 0x80) << 8;
*write_data_b++ = *write_data;
read_end = data + gus_sample->data_length;
if (read_data != read_end) {
do {
*write_data_b++ = ((*read_data++) ^ 0x80) << 8;
} while (read_data != read_end);
}
gus_sample->loop_start += loop_length;
gus_sample->loop_end += dloop_length;
gus_sample->data_length = new_length;
gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_UNSIGNED;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 8bit unsigned reverse */
static int convert_8ur(unsigned char *data, struct _sample *gus_sample) {
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->data_length;
signed short int *write_data = NULL;
unsigned long int tmp_loop = 0;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc((gus_sample->data_length + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data + gus_sample->data_length - 1;
do {
*write_data-- = ((*read_data++) ^ 0x80) << 8;
} while (read_data != read_end);
tmp_loop = gus_sample->loop_end;
gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start;
gus_sample->loop_start = gus_sample->data_length - tmp_loop;
gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4)
| ((gus_sample->loop_fraction & 0xf0) >> 4);
gus_sample->modes ^= SAMPLE_REVERSE | SAMPLE_UNSIGNED;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 8bit unsigned reverse ping pong */
static int convert_8urp(unsigned char *data, struct _sample *gus_sample) {
unsigned long int loop_length = gus_sample->loop_end
- gus_sample->loop_start;
unsigned long int dloop_length = loop_length * 2;
unsigned long int new_length = gus_sample->data_length + dloop_length;
unsigned char *read_data = data + gus_sample->data_length - 1;
unsigned char *read_end = data + gus_sample->loop_end;
signed short int *write_data = NULL;
signed short int *write_data_a = NULL;
signed short int *write_data_b = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc((new_length + 2), sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data++ = ((*read_data--) ^ 0x80) << 8;
} while (read_data != read_end);
*write_data = ((*read_data--) ^ 0x80) << 8;
write_data_a = write_data + dloop_length;
*write_data_a-- = *write_data;
write_data++;
write_data_b = write_data + dloop_length;
read_end = data + gus_sample->loop_start;
do {
*write_data = ((*read_data--) ^ 0x80) << 8;
*write_data_a-- = *write_data;
*write_data_b++ = *write_data;
write_data++;
} while (read_data != read_end);
*write_data = ((*read_data--) ^ 0x80) << 8;
*write_data_b++ = *write_data;
read_end = data - 1;
do {
*write_data_b++ = ((*read_data--) ^ 0x80) << 8;
} while (read_data != read_end);
gus_sample->loop_start += loop_length;
gus_sample->loop_end += dloop_length;
gus_sample->data_length = new_length;
gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE | SAMPLE_UNSIGNED;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 16bit signed */
static int convert_16s(unsigned char *data, struct _sample *gus_sample) {
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->data_length;
signed short int *write_data = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data = *read_data++;
*write_data++ |= (*read_data++) << 8;
} while (read_data < read_end);
gus_sample->loop_start >>= 1;
gus_sample->loop_end >>= 1;
gus_sample->data_length >>= 1;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 16bit signed ping pong */
static int convert_16sp(unsigned char *data, struct _sample *gus_sample) {
unsigned long int loop_length = gus_sample->loop_end
- gus_sample->loop_start;
unsigned long int dloop_length = loop_length * 2;
unsigned long int new_length = gus_sample->data_length + dloop_length;
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->loop_start;
signed short int *write_data = NULL;
signed short int *write_data_a = NULL;
signed short int *write_data_b = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc(((new_length >> 1) + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data = (*read_data++);
*write_data++ |= (*read_data++) << 8;
} while (read_data < read_end);
*write_data = (*read_data++);
*write_data |= (*read_data++) << 8;
write_data_a = write_data + (dloop_length >> 1);
*write_data_a-- = *write_data;
write_data++;
write_data_b = write_data + (dloop_length >> 1);
read_end = data + gus_sample->loop_end;
do {
*write_data = (*read_data++);
*write_data |= (*read_data++) << 8;
*write_data_a-- = *write_data;
*write_data_b++ = *write_data;
write_data++;
} while (read_data < read_end);
*write_data = *(read_data++);
*write_data |= (*read_data++) << 8;
*write_data_b++ = *write_data;
read_end = data + gus_sample->data_length;
if (read_data != read_end) {
do {
*write_data_b = *(read_data++);
*write_data_b++ |= (*read_data++) << 8;
} while (read_data < read_end);
}
gus_sample->loop_start += loop_length;
gus_sample->loop_end += dloop_length;
gus_sample->data_length = new_length;
gus_sample->modes ^= SAMPLE_PINGPONG;
gus_sample->loop_start >>= 1;
gus_sample->loop_end >>= 1;
gus_sample->data_length >>= 1;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 16bit signed reverse */
static int convert_16sr(unsigned char *data, struct _sample *gus_sample) {
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->data_length;
signed short int *write_data = NULL;
unsigned long int tmp_loop = 0;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data + (gus_sample->data_length >> 1) - 1;
do {
*write_data = *read_data++;
*write_data-- |= (*read_data++) << 8;
} while (read_data < read_end);
tmp_loop = gus_sample->loop_end;
gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start;
gus_sample->loop_start = gus_sample->data_length - tmp_loop;
gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4)
| ((gus_sample->loop_fraction & 0xf0) >> 4);
gus_sample->loop_start >>= 1;
gus_sample->loop_end >>= 1;
gus_sample->data_length >>= 1;
gus_sample->modes ^= SAMPLE_REVERSE;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 16bit signed reverse ping pong */
static int convert_16srp(unsigned char *data, struct _sample *gus_sample) {
unsigned long int loop_length = gus_sample->loop_end
- gus_sample->loop_start;
unsigned long int dloop_length = loop_length * 2;
unsigned long int new_length = gus_sample->data_length + dloop_length;
unsigned char *read_data = data + gus_sample->data_length - 1;
unsigned char *read_end = data + gus_sample->loop_end;
signed short int *write_data = NULL;
signed short int *write_data_a = NULL;
signed short int *write_data_b = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc(((new_length >> 1) + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data = (*read_data--) << 8;
*write_data++ |= *read_data--;
} while (read_data < read_end);
*write_data = (*read_data-- << 8);
*write_data |= *read_data--;
write_data_a = write_data + (dloop_length >> 1);
*write_data_a-- = *write_data;
write_data++;
write_data_b = write_data + (dloop_length >> 1);
read_end = data + gus_sample->loop_start;
do {
*write_data = (*read_data--) << 8;
*write_data |= *read_data--;
*write_data_a-- = *write_data;
*write_data_b++ = *write_data;
write_data++;
} while (read_data < read_end);
*write_data = ((*read_data--) << 8);
*write_data |= *read_data--;
*write_data_b++ = *write_data;
read_end = data - 1;
do {
*write_data_b = (*read_data--) << 8;
*write_data_b++ |= *read_data--;
} while (read_data < read_end);
gus_sample->loop_start += loop_length;
gus_sample->loop_end += dloop_length;
gus_sample->data_length = new_length;
gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 16bit unsigned */
static int convert_16u(unsigned char *data, struct _sample *gus_sample) {
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->data_length;
signed short int *write_data = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data = *read_data++;
*write_data++ |= ((*read_data++) ^ 0x80) << 8;
} while (read_data < read_end);
gus_sample->loop_start >>= 1;
gus_sample->loop_end >>= 1;
gus_sample->data_length >>= 1;
gus_sample->modes ^= SAMPLE_UNSIGNED;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 16bit unsigned ping pong */
static int convert_16up(unsigned char *data, struct _sample *gus_sample) {
unsigned long int loop_length = gus_sample->loop_end
- gus_sample->loop_start;
unsigned long int dloop_length = loop_length * 2;
unsigned long int new_length = gus_sample->data_length + dloop_length;
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->loop_start;
signed short int *write_data = NULL;
signed short int *write_data_a = NULL;
signed short int *write_data_b = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc(((new_length >> 1) + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data = (*read_data++);
*write_data++ |= ((*read_data++) ^ 0x80) << 8;
} while (read_data < read_end);
*write_data = (*read_data++);
*write_data |= ((*read_data++) ^ 0x80) << 8;
write_data_a = write_data + (dloop_length >> 1);
*write_data_a-- = *write_data;
write_data++;
write_data_b = write_data + (dloop_length >> 1);
read_end = data + gus_sample->loop_end;
do {
*write_data = (*read_data++);
*write_data |= ((*read_data++) ^ 0x80) << 8;
*write_data_a-- = *write_data;
*write_data_b++ = *write_data;
write_data++;
} while (read_data < read_end);
*write_data = (*read_data++);
*write_data |= ((*read_data++) ^ 0x80) << 8;
*write_data_b++ = *write_data;
read_end = data + gus_sample->data_length;
if (read_data != read_end) {
do {
*write_data_b = (*read_data++);
*write_data_b++ |= ((*read_data++) ^ 0x80) << 8;
} while (read_data < read_end);
}
gus_sample->loop_start += loop_length;
gus_sample->loop_end += dloop_length;
gus_sample->data_length = new_length;
gus_sample->modes ^= SAMPLE_PINGPONG;
gus_sample->loop_start >>= 1;
gus_sample->loop_end >>= 1;
gus_sample->data_length >>= 1;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 16bit unsigned reverse */
static int convert_16ur(unsigned char *data, struct _sample *gus_sample) {
unsigned char *read_data = data;
unsigned char *read_end = data + gus_sample->data_length;
signed short int *write_data = NULL;
unsigned long int tmp_loop = 0;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc(((gus_sample->data_length >> 1) + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data + (gus_sample->data_length >> 1) - 1;
do {
*write_data = *read_data++;
*write_data-- |= ((*read_data++) ^ 0x80) << 8;
} while (read_data < read_end);
tmp_loop = gus_sample->loop_end;
gus_sample->loop_end = gus_sample->data_length - gus_sample->loop_start;
gus_sample->loop_start = gus_sample->data_length - tmp_loop;
gus_sample->loop_fraction = ((gus_sample->loop_fraction & 0x0f) << 4)
| ((gus_sample->loop_fraction & 0xf0) >> 4);
gus_sample->loop_start >>= 1;
gus_sample->loop_end >>= 1;
gus_sample->data_length >>= 1;
gus_sample->modes ^= SAMPLE_REVERSE | SAMPLE_UNSIGNED;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* 16bit unsigned reverse ping pong */
static int convert_16urp(unsigned char *data, struct _sample *gus_sample) {
unsigned long int loop_length = gus_sample->loop_end
- gus_sample->loop_start;
unsigned long int dloop_length = loop_length * 2;
unsigned long int new_length = gus_sample->data_length + dloop_length;
unsigned char *read_data = data + gus_sample->data_length - 1;
unsigned char *read_end = data + gus_sample->loop_end;
signed short int *write_data = NULL;
signed short int *write_data_a = NULL;
signed short int *write_data_b = NULL;
SAMPLE_CONVERT_DEBUG(__FUNCTION__);
gus_sample->data = (short*)calloc(((new_length >> 1) + 2),
sizeof(signed short int));
if (gus_sample->data != NULL) {
write_data = gus_sample->data;
do {
*write_data = ((*read_data--) ^ 0x80) << 8;
*write_data++ |= *read_data--;
} while (read_data < read_end);
*write_data = ((*read_data--) ^ 0x80) << 8;
*write_data |= *read_data--;
write_data_a = write_data + (dloop_length >> 1);
*write_data_a-- = *write_data;
write_data++;
write_data_b = write_data + (dloop_length >> 1);
read_end = data + gus_sample->loop_start;
do {
*write_data = ((*read_data--) ^ 0x80) << 8;
*write_data |= *read_data--;
*write_data_a-- = *write_data;
*write_data_b++ = *write_data;
write_data++;
} while (read_data < read_end);
*write_data = ((*read_data--) ^ 0x80) << 8;
*write_data |= *read_data--;
*write_data_b++ = *write_data;
read_end = data - 1;
do {
*write_data_b = ((*read_data--) ^ 0x80) << 8;
*write_data_b++ |= *read_data--;
} while (read_data < read_end);
gus_sample->loop_start += loop_length;
gus_sample->loop_end += dloop_length;
gus_sample->data_length = new_length;
gus_sample->modes ^= SAMPLE_PINGPONG | SAMPLE_REVERSE | SAMPLE_UNSIGNED;
return 0;
}
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, "to parse sample", errno);
return -1;
}
/* sample loading */
struct _sample * _WM_load_gus_pat(const char *filename, int fix_release) {
unsigned char *gus_patch;
unsigned long int gus_size;
unsigned long int gus_ptr;
unsigned char no_of_samples;
struct _sample *gus_sample = NULL;
struct _sample *first_gus_sample = NULL;
unsigned long int i = 0;
int (*do_convert[])(unsigned char *data, struct _sample *gus_sample) = {
convert_8s,
convert_16s,
convert_8u,
convert_16u,
convert_8sp,
convert_16sp,
convert_8up,
convert_16up,
convert_8sr,
convert_16sr,
convert_8ur,
convert_16ur,
convert_8srp,
convert_16srp,
convert_8urp,
convert_16urp
};
unsigned long int tmp_loop;
SAMPLE_CONVERT_DEBUG(__FUNCTION__); SAMPLE_CONVERT_DEBUG(filename);
if ((gus_patch = _WM_BufferFile(filename, &gus_size)) == NULL) {
return NULL;
}
if (gus_size < 239) {
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_CORUPT, "(too short)", 0);
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0);
free(gus_patch);
return NULL;
}
if (memcmp(gus_patch, "GF1PATCH110\0ID#000002", 22)
&& memcmp(gus_patch, "GF1PATCH100\0ID#000002", 22)) {
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(unsupported format)",
0);
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0);
free(gus_patch);
return NULL;
}
if (gus_patch[82] > 1) {
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(unsupported format)",
0);
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0);
free(gus_patch);
return NULL;
}
if (gus_patch[151] > 1) {
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_INVALID, "(unsupported format)",
0);
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0);
free(gus_patch);
return NULL;
}
GUSPAT_FILENAME_DEBUG(filename); GUSPAT_INT_DEBUG("voices",gus_patch[83]);
no_of_samples = gus_patch[198];
gus_ptr = 239;
while (no_of_samples) {
unsigned long int tmp_cnt;
if (first_gus_sample == NULL) {
first_gus_sample = (struct _sample*)malloc(sizeof(struct _sample));
gus_sample = first_gus_sample;
} else {
gus_sample->next = (struct _sample*)malloc(sizeof(struct _sample));
gus_sample = gus_sample->next;
}
if (gus_sample == NULL) {
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_MEM, NULL, 0);
_WM_ERROR(__FUNCTION__, __LINE__, WM_ERR_LOAD, filename, 0);
free(gus_patch);
return NULL;
}
gus_sample->next = NULL;
gus_sample->loop_fraction = gus_patch[gus_ptr + 7];
gus_sample->data_length = (gus_patch[gus_ptr + 11] << 24)
| (gus_patch[gus_ptr + 10] << 16)
| (gus_patch[gus_ptr + 9] << 8) | gus_patch[gus_ptr + 8];
gus_sample->loop_start = (gus_patch[gus_ptr + 15] << 24)
| (gus_patch[gus_ptr + 14] << 16)
| (gus_patch[gus_ptr + 13] << 8) | gus_patch[gus_ptr + 12];
gus_sample->loop_end = (gus_patch[gus_ptr + 19] << 24)
| (gus_patch[gus_ptr + 18] << 16)
| (gus_patch[gus_ptr + 17] << 8) | gus_patch[gus_ptr + 16];
gus_sample->rate = (gus_patch[gus_ptr + 21] << 8)
| gus_patch[gus_ptr + 20];
gus_sample->freq_low = ((gus_patch[gus_ptr + 25] << 24)
| (gus_patch[gus_ptr + 24] << 16)
| (gus_patch[gus_ptr + 23] << 8) | gus_patch[gus_ptr + 22]);
gus_sample->freq_high = ((gus_patch[gus_ptr + 29] << 24)
| (gus_patch[gus_ptr + 28] << 16)
| (gus_patch[gus_ptr + 27] << 8) | gus_patch[gus_ptr + 26]);
gus_sample->freq_root = ((gus_patch[gus_ptr + 33] << 24)
| (gus_patch[gus_ptr + 32] << 16)
| (gus_patch[gus_ptr + 31] << 8) | gus_patch[gus_ptr + 30]);
/* This is done this way instead of ((freq * 1024) / rate) to avoid 32bit overflow. */
/* Result is 0.001% inacurate */
gus_sample->inc_div = ((gus_sample->freq_root * 512) / gus_sample->rate) * 2;
#if 0
/* We dont use this info at this time, kept in here for info */
printf("\rTremolo Sweep: %i, Rate: %i, Depth %i\n",
gus_patch[gus_ptr+49], gus_patch[gus_ptr+50], gus_patch[gus_ptr+51]);
printf("\rVibrato Sweep: %i, Rate: %i, Depth %i\n",
gus_patch[gus_ptr+52], gus_patch[gus_ptr+53], gus_patch[gus_ptr+54]);
#endif
gus_sample->modes = gus_patch[gus_ptr + 55];
GUSPAT_START_DEBUG(); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_16BIT, "16bit "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_UNSIGNED, "Unsigned "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_LOOP, "Loop "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_PINGPONG, "PingPong "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_REVERSE, "Reverse "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_SUSTAIN, "Sustain "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_ENVELOPE, "Envelope "); GUSPAT_MODE_DEBUG(gus_patch[gus_ptr+55], SAMPLE_CLAMPED, "Clamped "); GUSPAT_END_DEBUG();
if (gus_sample->loop_start > gus_sample->loop_end) {
tmp_loop = gus_sample->loop_end;
gus_sample->loop_end = gus_sample->loop_start;
gus_sample->loop_start = tmp_loop;
gus_sample->loop_fraction =
((gus_sample->loop_fraction & 0x0f) << 4)
| ((gus_sample->loop_fraction & 0xf0) >> 4);
}
/*
FIXME: Experimental Hacky Fix
*/
if (fix_release) {
if (env_time_table[gus_patch[gus_ptr + 40]]
< env_time_table[gus_patch[gus_ptr + 41]]) {
unsigned char tmp_hack_rate = gus_patch[gus_ptr + 41];
gus_patch[gus_ptr + 41] = gus_patch[gus_ptr + 40];
gus_patch[gus_ptr + 40] = tmp_hack_rate;
}
}
for (i = 0; i < 6; i++) {
if (gus_sample->modes & SAMPLE_ENVELOPE) {
unsigned char env_rate = gus_patch[gus_ptr + 37 + i];
gus_sample->env_target[i] = 16448 * gus_patch[gus_ptr + 43 + i];
GUSPAT_INT_DEBUG("Envelope Level",gus_patch[gus_ptr+43+i]); GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[env_rate]);
gus_sample->env_rate[i] = (signed long int) (4194303.0
/ ((float) _WM_SampleRate * env_time_table[env_rate]));
GUSPAT_INT_DEBUG("Envelope Rate",gus_sample->env_rate[i]); GUSPAT_INT_DEBUG("GUSPAT Rate",env_rate);
if (gus_sample->env_rate[i] == 0) {
_WM_ERROR_NEW("%s: Warning: found invalid envelope(%lu) rate setting in %s. Using %f instead.",
__FUNCTION__, i, filename, env_time_table[63]);
gus_sample->env_rate[i] = (signed long int) (4194303.0
/ ((float) _WM_SampleRate * env_time_table[63]));
GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[63]);
}
} else {
gus_sample->env_target[i] = 4194303;
gus_sample->env_rate[i] = (signed long int) (4194303.0
/ ((float) _WM_SampleRate * env_time_table[63]));
GUSPAT_FLOAT_DEBUG("Envelope Time",env_time_table[63]);
}
}
gus_sample->env_target[6] = 0;
gus_sample->env_rate[6] = (signed long int) (4194303.0
/ ((float) _WM_SampleRate * env_time_table[63]));
gus_ptr += 96;
tmp_cnt = gus_sample->data_length;
if (do_convert[(((gus_sample->modes & 0x18) >> 1)
| (gus_sample->modes & 0x03))](&gus_patch[gus_ptr], gus_sample)
== -1) {
free(gus_patch);
return NULL;
}
gus_ptr += tmp_cnt;
gus_sample->loop_start = (gus_sample->loop_start << 10)
| (((gus_sample->loop_fraction & 0x0f) << 10) / 16);
gus_sample->loop_end = (gus_sample->loop_end << 10)
| (((gus_sample->loop_fraction & 0xf0) << 6) / 16);
gus_sample->loop_size = gus_sample->loop_end - gus_sample->loop_start;
gus_sample->data_length = gus_sample->data_length << 10;
no_of_samples--;
}
free(gus_patch);
return first_gus_sample;
}

77
src/wildmidi/gus_pat.h Normal file
View file

@ -0,0 +1,77 @@
/*
gus_pat.h
Midi Wavetable Processing library
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef __GUS_PAT_H
#define __GUS_PAT_H
/* Guspat Envelope Rate Timings */
static float env_time_table[] = {
/* Row 1 = (4095.0 / (x * ( 1.0 / (1.6 * 14.0) ))) / 1000000.0 */
0.0f, 0.091728000f, 0.045864000f, 0.030576000f, 0.022932000f, 0.018345600f, 0.015288000f, 0.013104000f,
0.011466000f, 0.010192000f, 0.009172800f, 0.008338909f, 0.007644000f, 0.007056000f, 0.006552000f, 0.006115200f,
0.005733000f, 0.005395765f, 0.005096000f, 0.004827789f, 0.004586400f, 0.004368000f, 0.004169455f, 0.003988174f,
0.003822000f, 0.003669120f, 0.003528000f, 0.003397333f, 0.003276000f, 0.003163034f, 0.003057600f, 0.002958968f,
0.002866500f, 0.002779636f, 0.002697882f, 0.002620800f, 0.002548000f, 0.002479135f, 0.002413895f, 0.002352000f,
0.002293200f, 0.002237268f, 0.002184000f, 0.002133209f, 0.002084727f, 0.002038400f, 0.001994087f, 0.001951660f,
0.001911000f, 0.001872000f, 0.001834560f, 0.001798588f, 0.001764000f, 0.001730717f, 0.001698667f, 0.001667782f,
0.001638000f, 0.001609263f, 0.001581517f, 0.001554712f, 0.001528800f, 0.001503738f, 0.001479484f, 0.001456000f,
/* Row 2 = (4095.0 / (x * ((1.0 / (1.6 * 14.0)) / 8.0 ))) / 1000000.0 */
0.0f, 0.733824000f, 0.366912000f, 0.244608000f, 0.183456000f, 0.146764800f, 0.122304000f, 0.104832000f,
0.091728000f, 0.081536000f, 0.073382400f, 0.066711273f, 0.061152000f, 0.056448000f, 0.052416000f, 0.048921600f,
0.045864000f, 0.043166118f, 0.040768000f, 0.038622316f, 0.036691200f, 0.034944000f, 0.033355636f, 0.031905391f,
0.030576000f, 0.029352960f, 0.028224000f, 0.027178667f, 0.026208000f, 0.025304276f, 0.024460800f, 0.023671742f,
0.022932000f, 0.022237091f, 0.021583059f, 0.020966400f, 0.020384000f, 0.019833081f, 0.019311158f, 0.018816000f,
0.018345600f, 0.017898146f, 0.017472000f, 0.017065674f, 0.016677818f, 0.016307200f, 0.015952696f, 0.015613277f,
0.015288000f, 0.014976000f, 0.014676480f, 0.014388706f, 0.014112000f, 0.013845736f, 0.013589333f, 0.013342255f,
0.013104000f, 0.012874105f, 0.012652138f, 0.012437695f, 0.012230400f, 0.012029902f, 0.011835871f, 0.011648000f,
/* Row 3 = (4095.0 / (x * ((1.0 / (1.6 * 14.0)) / 64.0 ))) / 1000000.0 */
0.0f, 5.870592000f, 2.935296000f, 1.956864000f, 1.467648000f, 1.174118400f, 0.978432000f, 0.838656000f,
0.733824000f, 0.652288000f, 0.587059200f, 0.533690182f, 0.489216000f, 0.451584000f, 0.419328000f, 0.391372800f,
0.366912000f, 0.345328941f, 0.326144000f, 0.308978526f, 0.293529600f, 0.279552000f, 0.266845091f, 0.255243130f,
0.244608000f, 0.234823680f, 0.225792000f, 0.217429333f, 0.209664000f, 0.202434207f, 0.195686400f, 0.189373935f,
0.183456000f, 0.177896727f, 0.172664471f, 0.167731200f, 0.163072000f, 0.158664649f, 0.154489263f, 0.150528000f,
0.146764800f, 0.143185171f, 0.139776000f, 0.136525395f, 0.133422545f, 0.130457600f, 0.127621565f, 0.124906213f,
0.122304000f, 0.119808000f, 0.117411840f, 0.115109647f, 0.112896000f, 0.110765887f, 0.108714667f, 0.106738036f,
0.104832000f, 0.102992842f, 0.101217103f, 0.099501559f, 0.097843200f, 0.096239213f, 0.094686968f, 0.093184000f,
/* Row 4 = (4095.0 / (x * ((1.0 / (1.6 * 14.0)) / 512.0))) / 1000000.0 */
0.0f, 46.964736000f,23.482368000f,15.654912000f,11.741184000f, 9.392947200f, 7.827456000f, 6.709248000f,
5.870592000f, 5.218304000f, 4.696473600f, 4.269521455f, 3.913728000f, 3.612672000f, 3.354624000f, 3.130982400f,
2.935296000f, 2.762631529f, 2.609152000f, 2.471828211f, 2.348236800f, 2.236416000f, 2.134760727f, 2.041945043f,
1.956864000f, 1.878589440f, 1.806336000f, 1.739434667f, 1.677312000f, 1.619473655f, 1.565491200f, 1.514991484f,
1.467648000f, 1.423173818f, 1.381315765f, 1.341849600f, 1.304576000f, 1.269317189f, 1.235914105f, 1.204224000f,
1.174118400f, 1.145481366f, 1.118208000f, 1.092203163f, 1.067380364f, 1.043660800f, 1.020972522f, 0.999249702f,
0.978432000f, 0.958464000f, 0.939294720f, 0.920877176f, 0.903168000f, 0.886127094f, 0.869717333f, 0.853904291f,
0.838656000f, 0.823942737f, 0.809736828f, 0.796012475f, 0.782745600f, 0.769913705f, 0.757495742f, 0.745472000f
};
extern struct _sample * _WM_load_gus_pat (const char *filename, int _fix_release);
#endif /* __GUS_PAT_H */

398
src/wildmidi/reverb.cpp Normal file
View file

@ -0,0 +1,398 @@
/*
reverb.c
Midi Wavetable Processing library
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
//#include "config.h"
#include <math.h>
#include <stdlib.h>
#include "common.h"
#include "reverb.h"
/*
reverb function
*/
void _WM_reset_reverb(struct _rvb *rvb) {
int i, j, k;
for (i = 0; i < rvb->l_buf_size; i++) {
rvb->l_buf[i] = 0;
}
for (i = 0; i < rvb->r_buf_size; i++) {
rvb->r_buf[i] = 0;
}
for (k = 0; k < 8; k++) {
for (i = 0; i < 6; i++) {
for (j = 0; j < 2; j++) {
rvb->l_buf_flt_in[k][i][j] = 0;
rvb->l_buf_flt_out[k][i][j] = 0;
rvb->r_buf_flt_in[k][i][j] = 0;
rvb->r_buf_flt_out[k][i][j] = 0;
}
}
}
}
/*
_WM_init_reverb
=========================
Engine Description
8 reflective points around the room
2 speaker positions
1 listener position
Sounds come from the speakers to all points and to the listener.
Sound comes from the reflective points to the listener.
These sounds are combined, put through a filter that mimics surface absorbtion.
The combined sounds are also sent to the reflective points on the opposite side.
*/
struct _rvb *
_WM_init_reverb(int rate, float room_x, float room_y, float listen_x,
float listen_y) {
/* filters set at 125Hz, 250Hz, 500Hz, 1000Hz, 2000Hz, 4000Hz */
double Freq[] = {125.0, 250.0, 500.0, 1000.0, 2000.0, 4000.0};
/* numbers calculated from
* 101.325 kPa, 20 deg C, 50% relative humidity */
double dbAirAbs[] = {-0.00044, -0.00131, -0.002728, -0.004665, -0.009887, -0.029665};
/* modify these to adjust the absorption qualities of the surface.
* Remember that lower frequencies are less effected by surfaces
* Note: I am currently playing with the values and finding the ideal surfaces
* for nice default reverb.
*/
double dbAttn[8][6] = {
{-1.839, -6.205, -8.891, -12.059, -15.935, -20.942},
{-0.131, -6.205, -12.059, -20.933, -20.933, -15.944},
{-0.131, -6.205, -12.059, -20.933, -20.933, -15.944},
{-1.839, -6.205, -8.891, -12.059, -15.935, -20.942},
{-1.839, -6.205, -8.891, -12.059, -15.935, -20.942},
{-0.131, -6.205, -12.059, -20.933, -20.933, -15.944},
{-0.131, -6.205, -12.059, -20.933, -20.933, -15.944},
{-1.839, -6.205, -8.891, -12.059, -15.935, -20.942}
};
/*
double dbAttn[6] = {
// concrete covered in carpet
// -0.175, -0.537, -1.412, -4.437, -7.959, -7.959
// pleated drapes
-0.630, -3.223, -5.849, -12.041, -10.458, -7.959
};
*/
/* distance */
double SPL_DST[8] = {0.0};
double SPR_DST[8] = {0.0};
double RFN_DST[8] = {0.0};
double MAXL_DST = 0.0;
double MAXR_DST = 0.0;
double SPL_LSN_XOFS = 0.0;
double SPL_LSN_YOFS = 0.0;
double SPL_LSN_DST = 0.0;
double SPR_LSN_XOFS = 0.0;
double SPR_LSN_YOFS = 0.0;
double SPR_LSN_DST = 0.0;
struct _rvb *rtn_rvb = (struct _rvb*)malloc(sizeof(struct _rvb));
int j = 0;
int i = 0;
struct _coord {
double x;
double y;
};
#if 0
struct _coord SPL = {2.5, 5.0}; /* Left Speaker Position */
struct _coord SPR = {7.5, 5.0}; /* Right Speaker Position */
/* position of the reflective points */
struct _coord RFN[] = {
{ 5.0, 0.0},
{ 0.0, 6.66666},
{ 0.0, 13.3333},
{ 5.0, 20.0},
{ 10.0, 20.0},
{ 15.0, 13.3333},
{ 15.0, 6.66666},
{ 10.0, 0.0}
};
#else
struct _coord SPL; /* Left Speaker Position */
struct _coord SPR; /* Right Speaker Position */
/* position of the reflective points */
struct _coord RFN[8];
SPL.x = room_x / 4.0;
SPR.x = room_x / 4.0 * 3.0;
SPL.y = room_y / 10.0;
SPR.y = room_y / 10.0;
RFN[0].x = room_x / 3.0;
RFN[0].y = 0.0;
RFN[1].x = 0.0;
RFN[1].y = room_y / 3.0;
RFN[2].x = 0.0;
RFN[2].y = room_y / 3.0 * 2.0;
RFN[3].x = room_x / 3.0;
RFN[3].y = room_y;
RFN[4].x = room_x / 3.0 * 2.0;
RFN[4].y = room_y;
RFN[5].x = room_x;
RFN[5].y = room_y / 3.0 * 2.0;
RFN[6].x = room_x;
RFN[6].y = room_y / 3.0;
RFN[7].x = room_x / 3.0 * 2.0;
RFN[7].y = 0.0;
#endif
SPL_LSN_XOFS = SPL.x - listen_x;
SPL_LSN_YOFS = SPL.y - listen_y;
SPL_LSN_DST = sqrt((SPL_LSN_XOFS * SPL_LSN_XOFS) + (SPL_LSN_YOFS * SPL_LSN_YOFS));
if (SPL_LSN_DST > MAXL_DST)
MAXL_DST = SPL_LSN_DST;
SPR_LSN_XOFS = SPR.x - listen_x;
SPR_LSN_YOFS = SPR.y - listen_y;
SPR_LSN_DST = sqrt((SPR_LSN_XOFS * SPR_LSN_XOFS) + (SPR_LSN_YOFS * SPR_LSN_YOFS));
if (SPR_LSN_DST > MAXR_DST)
MAXR_DST = SPR_LSN_DST;
if (rtn_rvb == NULL) {
return NULL;
}
for (j = 0; j < 8; j++) {
double SPL_RFL_XOFS = 0;
double SPL_RFL_YOFS = 0;
double SPR_RFL_XOFS = 0;
double SPR_RFL_YOFS = 0;
double RFN_XOFS = listen_x - RFN[j].x;
double RFN_YOFS = listen_y - RFN[j].y;
RFN_DST[j] = sqrt((RFN_XOFS * RFN_XOFS) + (RFN_YOFS * RFN_YOFS));
SPL_RFL_XOFS = SPL.x - RFN[i].x;
SPL_RFL_YOFS = SPL.y - RFN[i].y;
SPR_RFL_XOFS = SPR.x - RFN[i].x;
SPR_RFL_YOFS = SPR.y - RFN[i].y;
SPL_DST[i] = sqrt(
(SPL_RFL_XOFS * SPL_RFL_XOFS) + (SPL_RFL_YOFS * SPL_RFL_YOFS));
SPR_DST[i] = sqrt(
(SPR_RFL_XOFS * SPR_RFL_XOFS) + (SPR_RFL_YOFS * SPR_RFL_YOFS));
/*
add the 2 distances together and remove the speaker to listener distance
so we dont have to delay the initial output
*/
SPL_DST[i] += RFN_DST[i];
/* so i dont have to delay speaker output */
SPL_DST[i] -= SPL_LSN_DST;
if (i < 4) {
if (SPL_DST[i] > MAXL_DST)
MAXL_DST = SPL_DST[i];
} else {
if (SPL_DST[i] > MAXR_DST)
MAXR_DST = SPL_DST[i];
}
SPR_DST[i] += RFN_DST[i];
/* so i dont have to delay speaker output */
SPR_DST[i] -= SPR_LSN_DST;
if (i < 4) {
if (SPR_DST[i] > MAXL_DST)
MAXL_DST = SPR_DST[i];
} else {
if (SPR_DST[i] > MAXR_DST)
MAXR_DST = SPR_DST[i];
}
RFN_DST[j] *= 2.0;
if (j < 4) {
if (RFN_DST[j] > MAXL_DST)
MAXL_DST = RFN_DST[j];
} else {
if (RFN_DST[j] > MAXR_DST)
MAXR_DST = RFN_DST[j];
}
for (i = 0; i < 6; i++) {
double srate = (double) rate;
double bandwidth = 2.0;
double omega = 2.0 * M_PI * Freq[i] / srate;
double sn = sin(omega);
double cs = cos(omega);
double alpha = sn * sinh(M_LN2 / 2 * bandwidth * omega / sn);
double A = pow(10.0, ((/*dbAttn[i]*/dbAttn[j][i] +
(dbAirAbs[i] * RFN_DST[j])) / 40.0) );
/*
Peaking band EQ filter
*/
double b0 = 1 + (alpha * A);
double b1 = -2 * cs;
double b2 = 1 - (alpha * A);
double a0 = 1 + (alpha / A);
double a1 = -2 * cs;
double a2 = 1 - (alpha / A);
rtn_rvb->coeff[j][i][0] = (signed int) ((b0 / a0) * 1024.0);
rtn_rvb->coeff[j][i][1] = (signed int) ((b1 / a0) * 1024.0);
rtn_rvb->coeff[j][i][2] = (signed int) ((b2 / a0) * 1024.0);
rtn_rvb->coeff[j][i][3] = (signed int) ((a1 / a0) * 1024.0);
rtn_rvb->coeff[j][i][4] = (signed int) ((a2 / a0) * 1024.0);
}
}
/* init the reverb buffers */
rtn_rvb->l_buf_size = (int) ((float) rate * (MAXL_DST / 340.29));
rtn_rvb->l_buf = (int*)malloc(
sizeof(signed int) * (rtn_rvb->l_buf_size + 1));
rtn_rvb->l_out = 0;
rtn_rvb->r_buf_size = (int) ((float) rate * (MAXR_DST / 340.29));
rtn_rvb->r_buf = (int*)malloc(
sizeof(signed int) * (rtn_rvb->r_buf_size + 1));
rtn_rvb->r_out = 0;
for (i = 0; i < 4; i++) {
rtn_rvb->l_sp_in[i] = (int) ((float) rate * (SPL_DST[i] / 340.29));
rtn_rvb->l_sp_in[i + 4] = (int) ((float) rate
* (SPL_DST[i + 4] / 340.29));
rtn_rvb->r_sp_in[i] = (int) ((float) rate * (SPR_DST[i] / 340.29));
rtn_rvb->r_sp_in[i + 4] = (int) ((float) rate
* (SPR_DST[i + 4] / 340.29));
rtn_rvb->l_in[i] = (int) ((float) rate * (RFN_DST[i] / 340.29));
rtn_rvb->r_in[i] = (int) ((float) rate * (RFN_DST[i + 4] / 340.29));
}
rtn_rvb->gain = 4;
_WM_reset_reverb(rtn_rvb);
return rtn_rvb;
}
/* _WM_free_reverb - free up memory used for reverb */
void _WM_free_reverb(struct _rvb *rvb) {
if (!rvb) return;
free(rvb->l_buf);
free(rvb->r_buf);
free(rvb);
}
void _WM_do_reverb(struct _rvb *rvb, signed int *buffer, int size) {
int i, j, k;
signed int l_buf_flt = 0;
signed int r_buf_flt = 0;
signed int l_rfl = 0;
signed int r_rfl = 0;
int vol_div = 64;
for (i = 0; i < size; i += 2) {
signed int tmp_l_val = 0;
signed int tmp_r_val = 0;
/*
add the initial reflections
from each speaker, 4 to go the left, 4 go to the right buffers
*/
tmp_l_val = buffer[i] / vol_div;
tmp_r_val = buffer[i + 1] / vol_div;
for (j = 0; j < 4; j++) {
rvb->l_buf[rvb->l_sp_in[j]] += tmp_l_val;
rvb->l_sp_in[j] = (rvb->l_sp_in[j] + 1) % rvb->l_buf_size;
rvb->l_buf[rvb->r_sp_in[j]] += tmp_r_val;
rvb->r_sp_in[j] = (rvb->r_sp_in[j] + 1) % rvb->l_buf_size;
rvb->r_buf[rvb->l_sp_in[j + 4]] += tmp_l_val;
rvb->l_sp_in[j + 4] = (rvb->l_sp_in[j + 4] + 1) % rvb->r_buf_size;
rvb->r_buf[rvb->r_sp_in[j + 4]] += tmp_r_val;
rvb->r_sp_in[j + 4] = (rvb->r_sp_in[j + 4] + 1) % rvb->r_buf_size;
}
/*
filter the reverb output and add to buffer
*/
l_rfl = rvb->l_buf[rvb->l_out];
rvb->l_buf[rvb->l_out] = 0;
rvb->l_out = (rvb->l_out + 1) % rvb->l_buf_size;
r_rfl = rvb->r_buf[rvb->r_out];
rvb->r_buf[rvb->r_out] = 0;
rvb->r_out = (rvb->r_out + 1) % rvb->r_buf_size;
for (k = 0; k < 8; k++) {
for (j = 0; j < 6; j++) {
l_buf_flt = ((l_rfl * rvb->coeff[k][j][0])
+ (rvb->l_buf_flt_in[k][j][0] * rvb->coeff[k][j][1])
+ (rvb->l_buf_flt_in[k][j][1] * rvb->coeff[k][j][2])
- (rvb->l_buf_flt_out[k][j][0] * rvb->coeff[k][j][3])
- (rvb->l_buf_flt_out[k][j][1] * rvb->coeff[k][j][4]))
/ 1024;
rvb->l_buf_flt_in[k][j][1] = rvb->l_buf_flt_in[k][j][0];
rvb->l_buf_flt_in[k][j][0] = l_rfl;
rvb->l_buf_flt_out[k][j][1] = rvb->l_buf_flt_out[k][j][0];
rvb->l_buf_flt_out[k][j][0] = l_buf_flt;
buffer[i] += l_buf_flt / 8;
r_buf_flt = ((r_rfl * rvb->coeff[k][j][0])
+ (rvb->r_buf_flt_in[k][j][0] * rvb->coeff[k][j][1])
+ (rvb->r_buf_flt_in[k][j][1] * rvb->coeff[k][j][2])
- (rvb->r_buf_flt_out[k][j][0] * rvb->coeff[k][j][3])
- (rvb->r_buf_flt_out[k][j][1] * rvb->coeff[k][j][4]))
/ 1024;
rvb->r_buf_flt_in[k][j][1] = rvb->r_buf_flt_in[k][j][0];
rvb->r_buf_flt_in[k][j][0] = r_rfl;
rvb->r_buf_flt_out[k][j][1] = rvb->r_buf_flt_out[k][j][0];
rvb->r_buf_flt_out[k][j][0] = r_buf_flt;
buffer[i + 1] += r_buf_flt / 8;
}
}
/*
add filtered result back into the buffers but on the opposite side
*/
tmp_l_val = buffer[i + 1] / vol_div;
tmp_r_val = buffer[i] / vol_div;
for (j = 0; j < 4; j++) {
rvb->l_buf[rvb->l_in[j]] += tmp_l_val;
rvb->l_in[j] = (rvb->l_in[j] + 1) % rvb->l_buf_size;
rvb->r_buf[rvb->r_in[j]] += tmp_r_val;
rvb->r_in[j] = (rvb->r_in[j] + 1) % rvb->r_buf_size;
}
}
}

57
src/wildmidi/reverb.h Normal file
View file

@ -0,0 +1,57 @@
/*
reverb.h
Midi Wavetable Processing library
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef __REVERB_H
#define __REVERB_H
struct _rvb {
/* filter data */
signed int l_buf_flt_in[8][6][2];
signed int l_buf_flt_out[8][6][2];
signed int r_buf_flt_in[8][6][2];
signed int r_buf_flt_out[8][6][2];
signed int coeff[8][6][5];
/* buffer data */
signed int *l_buf;
signed int *r_buf;
int l_buf_size;
int r_buf_size;
int l_out;
int r_out;
int l_sp_in[8];
int r_sp_in[8];
int l_in[4];
int r_in[4];
int gain;
unsigned long int max_reverb_time;
};
extern void _WM_reset_reverb (struct _rvb *rvb);
extern struct _rvb *_WM_init_reverb(int rate, float room_x, float room_y, float listen_x, float listen_y);
extern void _WM_free_reverb (struct _rvb *rvb);
extern void _WM_do_reverb (struct _rvb *rvb, signed int *buffer, int size);
#endif /* __REVERB_H */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,87 @@
/*
wildmidi_lib.h
Midi Wavetable Processing library
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef WILDMIDI_LIB_H
#define WILDMIDI_LIB_H
#define WM_MO_LOG_VOLUME 0x0001
#define WM_MO_ENHANCED_RESAMPLING 0x0002
#define WM_MO_REVERB 0x0004
#define WM_MO_WHOLETEMPO 0x8000
#define WM_MO_ROUNDTEMPO 0x2000
#define WM_GS_VERSION 0x0001
#define WM_SYMBOL // we do not need this in ZDoom
/*
#if defined(__cplusplus)
extern "C" {
#endif
*/
struct _WM_Info {
char *copyright;
unsigned long int current_sample;
unsigned long int approx_total_samples;
unsigned short int mixer_options;
unsigned long int total_midi_time;
};
typedef void midi;
WM_SYMBOL const char * WildMidi_GetString (unsigned short int info);
WM_SYMBOL int WildMidi_Init (const char * config_file, unsigned short int rate, unsigned short int options);
WM_SYMBOL int WildMidi_MasterVolume (unsigned char master_volume);
WM_SYMBOL int WildMidi_SetOption (midi * handle, unsigned short int options, unsigned short int setting);
WM_SYMBOL int WildMidi_Close (midi * handle);
WM_SYMBOL int WildMidi_Shutdown (void);
WM_SYMBOL int WildMidi_GetSampleRate (void);
/*
#if defined(__cplusplus)
}
#endif
*/
class WildMidi_Renderer
{
public:
WildMidi_Renderer();
~WildMidi_Renderer();
void ShortEvent(int status, int parm1, int parm2);
void LongEvent(const unsigned char *data, int len);
void ComputeOutput(float *buffer, int len);
void LoadInstrument(int bank, int percussion, int instr);
int GetVoiceCount();
void SetOption(int opt, int set);
private:
void *handle;
};
#endif /* WILDMIDI_LIB_H */

86
src/wildmidi/wm_error.cpp Normal file
View file

@ -0,0 +1,86 @@
/*
wm_error.c
error reporting
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
//#include "config.h"
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "wm_error.h"
#include "doomtype.h"
#include "v_text.h"
void _WM_ERROR_NEW(const char * wmfmt, ...) {
va_list args;
fprintf(stderr, "\r");
va_start(args, wmfmt);
vfprintf(stderr, wmfmt, args);
va_end(args);
fprintf(stderr, "\n");
}
void _WM_ERROR(const char * func, unsigned int lne, int wmerno,
const char * wmfor, int error) {
static const char *errors[WM_ERR_MAX+1] = {
"No error",
"Unable to obtain memory",
"Unable to stat",
"Unable to load",
"Unable to open",
"Unable to read",
"Invalid or Unsuported file format",
"File corrupt",
"Library not Initialized",
"Invalid argument",
"Library Already Initialized",
"Not a midi file",
"Refusing to load unusually long file",
"Invalid error code"
};
if (wmerno < 0 || wmerno > WM_ERR_MAX)
wmerno = WM_ERR_MAX;
if (wmfor != NULL) {
if (error != 0) {
Printf(TEXTCOLOR_RED "libWildMidi(%s:%u): ERROR %s %s (%s)\n", func,
lne, errors[wmerno], wmfor, strerror(error));
} else {
Printf(TEXTCOLOR_RED "libWildMidi(%s:%u): ERROR %s %s\n", func, lne,
errors[wmerno], wmfor);
}
} else {
if (error != 0) {
Printf(TEXTCOLOR_RED "libWildMidi(%s:%u): ERROR %s (%s)\n", func, lne,
errors[wmerno], strerror(error));
} else {
Printf(TEXTCOLOR_RED "libWildMidi(%s:%u): ERROR %s\n", func, lne,
errors[wmerno]);
}
}
}

56
src/wildmidi/wm_error.h Normal file
View file

@ -0,0 +1,56 @@
/*
wm_error.h
error reporting
Copyright (C) Chris Ison 2001-2011
Copyright (C) Bret Curtis 2013-2014
This file is part of WildMIDI.
WildMIDI is free software: you can redistribute and/or modify the player
under the terms of the GNU General Public License and you can redistribute
and/or modify the library under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation, either version 3 of
the licenses, or(at your option) any later version.
WildMIDI 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 and
the GNU Lesser General Public License for more details.
You should have received a copy of the GNU General Public License and the
GNU Lesser General Public License along with WildMIDI. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef __WM_ERROR_H
#define __WM_ERROR_H
enum {
WM_ERR_NONE = 0,
WM_ERR_MEM,
WM_ERR_STAT,
WM_ERR_LOAD,
WM_ERR_OPEN,
WM_ERR_READ,
WM_ERR_INVALID,
WM_ERR_CORUPT,
WM_ERR_NOT_INIT,
WM_ERR_INVALID_ARG,
WM_ERR_ALR_INIT,
WM_ERR_NOT_MIDI,
WM_ERR_LONGFIL,
WM_ERR_MAX
};
extern void _WM_ERROR_NEW(const char * wmfmt, ...)
#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
;
extern void _WM_ERROR(const char * func, unsigned int lne, int wmerno,
const char * wmfor, int error);
#endif /* __WM_ERROR_H */

View file

@ -56,4 +56,12 @@ gameinfo
statscreen_enteringpatch = "WIENTER"
}
DoomEdNums
{
4001 = "$Player5Start"
4002 = "$Player6Start"
4003 = "$Player7Start"
4004 = "$Player8Start"
}
include "mapinfo/common.txt"

View file

@ -1604,7 +1604,6 @@ OptionMenu AdvSoundOptions
StaticText "GUS Emulation", 1
TextField "GUS config file", "midi_config"
Slider "MIDI voices", "midi_voices", 16, 256, 4, 0
Option "Emulate TiMidity", "midi_timiditylike", "OnOff"
Option "Read DMXGUS lumps", "midi_dmxgus", "OnOff"
Option "GUS memory size", "gus_memsize", "GusMemory"
StaticText " "
@ -1620,6 +1619,10 @@ OptionMenu AdvSoundOptions
Option "Reverb", "timidity_reverb", "OnOff"
Option "Chorus", "timidity_chorus", "OnOff"
Slider "Relative volume", "timidity_mastervolume", 0, 4, 0.2, 1
StaticText " "
StaticText "WildMidi", 1
TextField "WildMidi config file", "wildmidi_config"
Option "Reverb", "wildmidi_reverb", "OnOff"
}
/*=======================================

View file

@ -103,6 +103,9 @@ OptionValue "HqResizeModes"
4, "hq2x"
5, "hq3x"
6, "hq4x"
7, "hq2x MMX"
8, "hq3x MMX"
9, "hq4x MMX"
}
OptionValue "FogMode"

View file

@ -106,6 +106,7 @@
MapExports="true"
SubSystem="2"
StackReserveSize="0"
LargeAddressAware="2"
TerminalServerAware="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
@ -223,6 +224,7 @@
MapExports="true"
SubSystem="2"
StackReserveSize="0"
LargeAddressAware="2"
TerminalServerAware="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
@ -332,6 +334,7 @@
ProgramDatabaseFile=".\Debug/zdoomd.pdb"
SubSystem="2"
StackReserveSize="0"
LargeAddressAware="2"
TerminalServerAware="2"
SetChecksum="false"
TargetMachine="0"
@ -440,6 +443,7 @@
ProgramDatabaseFile=".\Debug/zdoomd.pdb"
SubSystem="2"
StackReserveSize="0"
LargeAddressAware="2"
TerminalServerAware="2"
SetChecksum="false"
TargetMachine="17"
@ -938,6 +942,10 @@
RelativePath=".\src\parsecontext.cpp"
>
</File>
<File
RelativePath=".\src\pathexpander.cpp"
>
</File>
<File
RelativePath=".\src\po_man.cpp"
>
@ -1475,6 +1483,10 @@
RelativePath=".\src\parsecontext.h"
>
</File>
<File
RelativePath=".\src\pathexpander.h"
>
</File>
<File
RelativePath=".\src\po_man.h"
>
@ -2589,6 +2601,10 @@
RelativePath=".\src\sound\music_timidity_mididevice.cpp"
>
</File>
<File
RelativePath=".\src\sound\music_wildmidi_mididevice.cpp"
>
</File>
<File
RelativePath=".\src\sound\music_win_mididevice.cpp"
>
@ -2785,6 +2801,62 @@
</File>
</Filter>
</Filter>
<Filter
Name="WildMidi"
>
<Filter
Name="Headers"
>
<File
RelativePath=".\src\wildmidi\common.h"
>
</File>
<File
RelativePath=".\src\wildmidi\file_io.h"
>
</File>
<File
RelativePath=".\src\wildmidi\gus_pat.h"
>
</File>
<File
RelativePath=".\src\wildmidi\reverb.h"
>
</File>
<File
RelativePath=".\src\wildmidi\wildmidi_lib.h"
>
</File>
<File
RelativePath=".\src\wildmidi\wm_error.h"
>
</File>
</Filter>
<Filter
Name="Source"
>
<File
RelativePath=".\src\wildmidi\file_io.cpp"
>
</File>
<File
RelativePath=".\src\wildmidi\gus_pat.cpp"
>
</File>
<File
RelativePath=".\src\wildmidi\reverb.cpp"
>
</File>
<File
RelativePath=".\src\wildmidi\wildmidi_lib.cpp"
>
</File>
<File
RelativePath=".\src\wildmidi\wm_error.cpp"
>
</File>
</Filter>
</Filter>
</Filter>
<Filter
Name="SDL Files"