Merge commit '772a5724313f2ad0bd6828fcc28545a9ee5e6068' into scripting

Conflicts:
	src/p_pspr.cpp
	src/thingdef/thingdef_codeptr.cpp
This commit is contained in:
Christoph Oelckers 2016-01-17 20:00:45 +01:00
commit cfcd2668cc
94 changed files with 6367 additions and 965 deletions

View file

@ -123,7 +123,7 @@ FIND_PACKAGE_HANDLE_STANDARD_ARGS( GME
if( MSVC )
# Eliminate unreferenced functions and data
# Perform identical COMDAT folding
set( REL_LINKER_FLAGS "/opt:ref /opt:icf /nodefaultlib:msvcrt /TSAWARE" )
set( REL_LINKER_FLAGS "/opt:ref /opt:icf /nodefaultlib:msvcrt /TSAWARE /LARGEADDRESSAWARE" )
# String pooling
# Function-level linking

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

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

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

@ -27,7 +27,8 @@ II. Implementation Semantics
II.A : Storage and Retrieval of Data
------------------------------------
No changes.
Any TEXTMAP lump in the described namespaces must be encoded in ISO 8859-1 which
as of this writing is the only character encoding supported by ZDoom.
-----------------------------------
II.B : Storage Within Archive Files

View file

@ -187,6 +187,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 )
@ -496,6 +497,11 @@ if( NOT MSVC )
add_definitions( -D__forceinline=inline )
endif( NOT MSVC )
# Fix stat in v140_xp (broken in RTM and Update 1 so far)
if( MSVC AND MSVC_VERSION EQUAL 1900 AND CMAKE_GENERATOR_TOOLSET STREQUAL "v140_xp" )
add_definitions( -D_stat64i32=VS14Stat )
endif( MSVC AND MSVC_VERSION EQUAL 1900 AND CMAKE_GENERATOR_TOOLSET STREQUAL "v140_xp" )
if( UNIX )
CHECK_LIBRARY_EXISTS( rt clock_gettime "" CLOCK_GETTIME_IN_RT )
if( NOT CLOCK_GETTIME_IN_RT )
@ -919,6 +925,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
@ -1095,6 +1102,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
@ -1137,6 +1145,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
@ -1283,6 +1296,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

@ -2224,6 +2224,154 @@ bool AM_Check3DFloors(line_t *line)
return false;
}
// [TP] Check whether a sector can trigger a special that satisfies the provided function.
// If found, specialptr and argsptr will be filled by the special and the arguments
// If needUseActivated is true, the special must be activated by use.
bool AM_checkSectorActions (sector_t *sector, bool (*function)(int, int *), int *specialptr, int **argsptr, bool needUseActivated)
{
for (ASectorAction* action = sector->SecActTarget; action; action = barrier_cast<ASectorAction *>(action->tracer))
{
if ((action->IsActivatedByUse() || false == needUseActivated)
&& (*function)(action->special, action->args)
&& action->CanTrigger (players[consoleplayer].mo))
{
*specialptr = action->special;
*argsptr = action->args;
return true;
}
}
return false;
}
// [TP] Check whether there's a boundary on the provided line for a special that satisfies the provided function.
// It's a boundary if the line can activate the special or the line's bordering sectors can activate it.
// If found, specialptr and argsptr will be filled with special and args if given.
bool AM_checkSpecialBoundary (line_t &line, bool (*function)(int, int *), int *specialptr = NULL, int **argsptr = NULL)
{
if (specialptr == NULL)
{
static int sink;
specialptr = &sink;
}
if (argsptr == NULL)
{
static int *sink;
argsptr = &sink;
}
// Check if the line special qualifies for this
if ((line.activation & SPAC_PlayerActivate) && (*function)(line.special, line.args))
{
*specialptr = line.special;
*argsptr = line.args;
return true;
}
// Check sector actions in the line's front sector -- the action has to be use-activated in order to
// show up if this is a one-sided line, because the player cannot trigger sector actions by crossing
// a one-sided line (since that's impossible, duh).
if (AM_checkSectorActions(line.frontsector, function, specialptr, argsptr, line.backsector == NULL))
return true;
// If it has a back sector, check sector actions in that.
return (line.backsector && AM_checkSectorActions(line.backsector, function, specialptr, argsptr, false));
}
bool AM_isTeleportSpecial (int special, int *)
{
return (special == Teleport ||
special == Teleport_NoFog ||
special == Teleport_ZombieChanger ||
special == Teleport_Line);
}
bool AM_isTeleportBoundary (line_t &line)
{
return AM_checkSpecialBoundary(line, &AM_isTeleportSpecial);
}
bool AM_isExitSpecial (int special, int *)
{
return (special == Teleport_NewMap ||
special == Teleport_EndGame ||
special == Exit_Normal ||
special == Exit_Secret);
}
bool AM_isExitBoundary (line_t& line)
{
return AM_checkSpecialBoundary(line, &AM_isExitSpecial);
}
bool AM_isTriggerSpecial (int special, int *)
{
return LineSpecialsInfo[special] != NULL
&& LineSpecialsInfo[special]->max_args >= 0
&& special != Door_Open
&& special != Door_Close
&& special != Door_CloseWaitOpen
&& special != Door_Raise
&& special != Door_Animated
&& special != Generic_Door;
}
bool AM_isTriggerBoundary (line_t &line)
{
return AM_checkSpecialBoundary(line, &AM_isTriggerSpecial);
}
bool AM_isLockSpecial (int special, int* args)
{
return special == Door_LockedRaise
|| special == ACS_LockedExecute
|| special == ACS_LockedExecuteDoor
|| (special == Door_Animated && args[3] != 0)
|| (special == Generic_Door && args[4] != 0)
|| (special == FS_Execute && args[2] != 0);
}
bool AM_isLockBoundary (line_t &line, int *lockptr = NULL)
{
if (lockptr == NULL)
{
static int sink;
lockptr = &sink;
}
if (line.locknumber)
{
*lockptr = line.locknumber;
return true;
}
int special;
int *args;
bool result = AM_checkSpecialBoundary(line, &AM_isLockSpecial, &special, &args);
if (result)
{
switch (special)
{
case FS_Execute:
*lockptr = args[2];
break;
case Door_Animated:
case Door_LockedRaise:
*lockptr = args[3];
break;
default:
*lockptr = args[4];
break;
}
}
return result;
}
//=============================================================================
//
// Determines visible lines, draws them.
@ -2272,48 +2420,18 @@ void AM_drawWalls (bool allmap)
else
AM_drawMline(&l, AMColors.WallColor);
}
else if (lines[i].locknumber > 0 && AMColors.displayLocks)
{ // [Dusk] specials w/ locknumbers
lock = lines[i].locknumber;
color = P_GetMapColorForLock(lock);
AMColor c;
if (color >= 0) c.FromRGB(RPART(color), GPART(color), BPART(color));
else c = AMColors[AMColors.LockedColor];
AM_drawMline (&l, c);
}
else if ((lines[i].special == Teleport ||
lines[i].special == Teleport_NoFog ||
lines[i].special == Teleport_ZombieChanger ||
lines[i].special == Teleport_Line) &&
(lines[i].activation & SPAC_PlayerActivate) &&
AMColors.isValid(AMColors.IntraTeleportColor))
else if (AM_isTeleportBoundary(lines[i]) && AMColors.isValid(AMColors.IntraTeleportColor))
{ // intra-level teleporters
AM_drawMline(&l, AMColors.IntraTeleportColor);
}
else if ((lines[i].special == Teleport_NewMap ||
lines[i].special == Teleport_EndGame ||
lines[i].special == Exit_Normal ||
lines[i].special == Exit_Secret) &&
AMColors.isValid(AMColors.InterTeleportColor))
else if (AM_isExitBoundary(lines[i]) && AMColors.isValid(AMColors.InterTeleportColor))
{ // inter-level/game-ending teleporters
AM_drawMline(&l, AMColors.InterTeleportColor);
}
else if (lines[i].special == Door_LockedRaise ||
lines[i].special == ACS_LockedExecute ||
lines[i].special == ACS_LockedExecuteDoor ||
(lines[i].special == Door_Animated && lines[i].args[3] != 0) ||
(lines[i].special == Generic_Door && lines[i].args[4] != 0))
else if (AM_isLockBoundary(lines[i], &lock))
{
if (AMColors.displayLocks)
{
int P_GetMapColorForLock(int lock);
if (lines[i].special==Door_LockedRaise || lines[i].special==Door_Animated)
lock=lines[i].args[3];
else lock=lines[i].args[4];
color = P_GetMapColorForLock(lock);
AMColor c;
@ -2328,16 +2446,9 @@ void AM_drawWalls (bool allmap)
AM_drawMline (&l, AMColors.LockedColor); // locked special
}
}
else if (am_showtriggerlines && AMColors.isValid(AMColors.SpecialWallColor)
&& LineSpecialsInfo[lines[i].special] != NULL
&& LineSpecialsInfo[lines[i].special]->max_args >= 0
&& lines[i].special != Door_Open
&& lines[i].special != Door_Close
&& lines[i].special != Door_CloseWaitOpen
&& lines[i].special != Door_Raise
&& lines[i].special != Door_Animated
&& lines[i].special != Generic_Door
&& (lines[i].activation & SPAC_PlayerActivate))
else if (am_showtriggerlines
&& AMColors.isValid(AMColors.SpecialWallColor)
&& AM_isTriggerBoundary(lines[i]))
{
AM_drawMline(&l, AMColors.SpecialWallColor); // wall with special non-door action the player can do
}

View file

@ -973,7 +973,7 @@ void NetUpdate (void)
{
I_StartTic ();
D_ProcessEvents ();
if ((maketic - gametic) / ticdup >= BACKUPTICS/2-1)
if (pauseext || (maketic - gametic) / ticdup >= BACKUPTICS/2-1)
break; // can't hold any more
//Printf ("mk:%i ",maketic);
@ -1204,7 +1204,7 @@ void NetUpdate (void)
// Send current network delay
// The number of tics we just made should be removed from the count.
netbuffer[k++] = ((maketic - newtics - gametic) / ticdup);
netbuffer[k++] = ((maketic - numtics - gametic) / ticdup);
if (numtics > 0)
{
@ -1810,7 +1810,8 @@ void TryRunTics (void)
// If paused, do not eat more CPU time than we need, because it
// will all be wasted anyway.
if (pauseext) r_NoInterpolate = true;
if (pauseext)
r_NoInterpolate = true;
bool doWait = cl_capfps || r_NoInterpolate /*|| netgame*/;
// get real tics
@ -1828,6 +1829,9 @@ void TryRunTics (void)
// get available tics
NetUpdate ();
if (pauseext)
return;
lowtic = INT_MAX;
numplaying = 0;
for (i = 0; i < doomcom.numnodes; i++)
@ -1935,7 +1939,7 @@ void TryRunTics (void)
C_Ticker ();
M_Ticker ();
I_GetTime (true);
if (!pauseext) G_Ticker();
G_Ticker();
gametic++;
NetUpdate (); // check for new console commands

View file

@ -242,6 +242,10 @@ enum
WF_WEAPONRELOADOK = 1 << 5, // [XA] Okay to reload this weapon.
WF_WEAPONZOOMOK = 1 << 6, // [XA] Okay to use weapon zoom function.
WF_REFIRESWITCHOK = 1 << 7, // Mirror WF_WEAPONSWITCHOK for A_ReFire
WF_USER1OK = 1 << 8, // [MC] Allow pushing of custom state buttons 1-4
WF_USER2OK = 1 << 9,
WF_USER3OK = 1 << 10,
WF_USER4OK = 1 << 11,
};
#define WPIECE1 1
@ -426,7 +430,7 @@ public:
int lastkilltime; // [RH] For multikills
BYTE multicount;
BYTE spreecount; // [RH] Keep track of killing sprees
BYTE WeaponState;
WORD WeaponState;
AWeapon *ReadyWeapon;
AWeapon *PendingWeapon; // WP_NOCHANGE if not changing

View file

@ -337,7 +337,7 @@ struct level_info_t
TArray<FSpecialAction> specialactions;
TArray<FSoundID> PrecacheSounds;
TArray<FTextureID> PrecacheTextures;
TArray<FString> PrecacheTextures;
level_info_t()
{

View file

@ -1077,15 +1077,8 @@ DEFINE_MAP_OPTION(PrecacheTextures, true)
do
{
parse.sc.MustGetString();
FTextureID tex = TexMan.CheckForTexture(parse.sc.String, FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable|FTextureManager::TEXMAN_TryAny|FTextureManager::TEXMAN_ReturnFirst);
if (!tex.isValid())
{
parse.sc.ScriptMessage("Unknown texture \"%s\"", parse.sc.String);
}
else
{
info->PrecacheTextures.Push(tex);
}
//the texture manager is not initialized here so all we can do is store the texture's name.
info->PrecacheTextures.Push(parse.sc.String);
} while (parse.sc.CheckString(","));
}

View file

@ -325,8 +325,7 @@ public:
virtual FState *GetReadyState ();
virtual FState *GetAtkState (bool hold);
virtual FState *GetAltAtkState (bool hold);
virtual FState *GetRelState ();
virtual FState *GetZoomState ();
virtual FState *GetStateForButtonName (FName button);
virtual void PostMorphWeapon ();
virtual void EndPowerup ();

View file

@ -39,6 +39,14 @@
IMPLEMENT_CLASS (ASectorAction)
ASectorAction::ASectorAction (bool activatedByUse) :
ActivatedByUse (activatedByUse) {}
bool ASectorAction::IsActivatedByUse() const
{
return ActivatedByUse;
}
void ASectorAction::Destroy ()
{
// Remove ourself from this sector's list of actions
@ -102,12 +110,17 @@ bool ASectorAction::DoTriggerAction (AActor *triggerer, int activationType)
return false;
}
bool ASectorAction::CanTrigger (AActor *triggerer) const
{
return special &&
((triggerer->player && !(flags & MF_FRIENDLY)) ||
((flags & MF_AMBUSH) && (triggerer->flags2 & MF2_MCROSS)) ||
((flags2 & MF2_DORMANT) && (triggerer->flags2 & MF2_PCROSS)));
}
bool ASectorAction::CheckTrigger (AActor *triggerer) const
{
if (special &&
((triggerer->player && !(flags & MF_FRIENDLY)) ||
((flags & MF_AMBUSH) && (triggerer->flags2 & MF2_MCROSS)) ||
((flags2 & MF2_DORMANT) && (triggerer->flags2 & MF2_PCROSS))))
if (CanTrigger(triggerer))
{
bool res = !!P_ExecuteSpecial(special, NULL, triggerer, false, args[0], args[1],
args[2], args[3], args[4]);
@ -196,6 +209,7 @@ class ASecActUse : public ASectorAction
{
DECLARE_CLASS (ASecActUse, ASectorAction)
public:
ASecActUse() : ASectorAction (true) {}
bool DoTriggerAction (AActor *triggerer, int activationType);
};
@ -214,6 +228,7 @@ class ASecActUseWall : public ASectorAction
{
DECLARE_CLASS (ASecActUseWall, ASectorAction)
public:
ASecActUseWall() : ASectorAction (true) {}
bool DoTriggerAction (AActor *triggerer, int activationType);
};

View file

@ -701,25 +701,15 @@ FState *AWeapon::GetAltAtkState (bool hold)
//===========================================================================
//
// AWeapon :: GetRelState
// AWeapon :: GetStateForButtonName
//
//===========================================================================
FState *AWeapon::GetRelState ()
FState *AWeapon::GetStateForButtonName (FName button)
{
return FindState(NAME_Reload);
return FindState(button);
}
//===========================================================================
//
// AWeapon :: GetZoomState
//
//===========================================================================
FState *AWeapon::GetZoomState ()
{
return FindState(NAME_Zoom);
}
/* Weapon giver ***********************************************************/

View file

@ -134,6 +134,7 @@ DHUDMessage::DHUDMessage (FFont *font, const char *text, float x, float y, int h
NoWrap = false;
ClipX = ClipY = ClipWidth = ClipHeight = 0;
WrapWidth = 0;
HandleAspect = true;
Top = y;
Next = NULL;
Lines = NULL;
@ -196,6 +197,14 @@ void DHUDMessage::Serialize (FArchive &arc)
NoWrap = false;
ClipX = ClipY = ClipWidth = ClipHeight = WrapWidth = 0;
}
if (SaveVersion >= 4525)
{
arc << HandleAspect;
}
else
{
HandleAspect = true;
}
if (arc.IsLoading ())
{
Lines = NULL;
@ -257,7 +266,7 @@ void DHUDMessage::CalcClipCoords(int hudheight)
else
{
screen->VirtualToRealCoordsInt(x, y, w, h,
HUDWidth, hudheight, false, true);
HUDWidth, hudheight, false, HandleAspect);
ClipLeft = x;
ClipTop = y;
ClipRight = x + w;

View file

@ -94,12 +94,13 @@ public:
NoWrap = nowrap;
ResetText(SourceText);
}
void SetClipRect(int x, int y, int width, int height)
void SetClipRect(int x, int y, int width, int height, bool aspect)
{
ClipX = x;
ClipY = y;
ClipWidth = width;
ClipHeight = height;
HandleAspect = aspect;
}
void SetWrapWidth(int wrap)
{
@ -119,6 +120,7 @@ protected:
int HUDWidth, HUDHeight;
int ClipX, ClipY, ClipWidth, ClipHeight, WrapWidth; // in HUD coords
int ClipLeft, ClipTop, ClipRight, ClipBot; // in screen coords
bool HandleAspect;
EColorRange TextColor;
FFont *Font;
FRenderStyle Style;

View file

@ -223,6 +223,10 @@ xx(Flash)
xx(AltFlash)
xx(Reload)
xx(Zoom)
xx(User1)
xx(User2)
xx(User3)
xx(User4)
// State names used by ASwitchableDecoration
xx(Active)

View file

@ -48,6 +48,7 @@
#define HALF_PI (PI*0.5)
EXTERN_CVAR(Int, opl_core)
extern int current_opl_core;
OPLio::~OPLio()
{
@ -323,7 +324,7 @@ int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3)
{
assert(numchips >= 1 && numchips <= countof(chips));
uint i;
IsOPL3 = (opl_core == 1 || opl_core == 2 || opl_core == 3);
IsOPL3 = (current_opl_core == 1 || current_opl_core == 2 || current_opl_core == 3);
memset(chips, 0, sizeof(chips));
if (IsOPL3)
@ -332,7 +333,7 @@ int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3)
}
for (i = 0; i < numchips; ++i)
{
OPLEmul *chip = IsOPL3 ? (opl_core == 1 ? DBOPLCreate(stereo) : (opl_core == 2 ? JavaOPLCreate(stereo) : NukedOPL3Create(stereo))) : YM3812Create(stereo);
OPLEmul *chip = IsOPL3 ? (current_opl_core == 1 ? DBOPLCreate(stereo) : (current_opl_core == 2 ? JavaOPLCreate(stereo) : NukedOPL3Create(stereo))) : YM3812Create(stereo);
if (chip == NULL)
{
break;

View file

@ -53,6 +53,7 @@
#endif
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
void OPL_SetCore(const char *args);
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
@ -76,8 +77,9 @@ CVAR(Bool, opl_fullpan, true, CVAR_ARCHIVE|CVAR_GLOBALCONFIG);
//
//==========================================================================
OPLMIDIDevice::OPLMIDIDevice()
OPLMIDIDevice::OPLMIDIDevice(const char *args)
{
OPL_SetCore(args);
FullPan = opl_fullpan;
FWadLump data = Wads.OpenLumpName("GENMIDI");
OPLloadBank(data);

View file

@ -262,6 +262,7 @@ protected:
//==========================================================================
OPLDumperMIDIDevice::OPLDumperMIDIDevice(const char *filename)
: OPLMIDIDevice(NULL)
{
// Replace the standard OPL device with a disk writer.
delete io;

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;
}
PClassActor *info = PClass::FindActor (type);
AInventory *item = activator->FindInventory (info);
if (max)
{
if (item)
return item->MaxAmount;
else
return ((AInventory *)GetDefaultByType (info))->MaxAmount;
}
return item ? item->Amount : 0;
}
@ -4441,6 +4456,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),
@ -5307,6 +5323,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, SDWORD *args, const
ClipRectWidth = argCount > 2 ? args[2] : 0;
ClipRectHeight = argCount > 3 ? args[3] : 0;
WrapWidth = argCount > 4 ? args[4] : 0;
HandleAspect = argCount > 5 ? !!args[5] : true;
break;
case ACSF_SetHUDWrapWidth:
@ -5906,11 +5923,19 @@ 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;
}
return 0;
}
@ -7846,7 +7871,7 @@ scriptwait:
}
break;
}
msg->SetClipRect(ClipRectLeft, ClipRectTop, ClipRectWidth, ClipRectHeight);
msg->SetClipRect(ClipRectLeft, ClipRectTop, ClipRectWidth, ClipRectHeight, HandleAspect);
if (WrapWidth != 0)
{
msg->SetWrapWidth(WrapWidth);
@ -8329,17 +8354,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;
@ -9458,6 +9483,7 @@ DLevelScript::DLevelScript (AActor *who, line_t *where, int num, const ScriptPtr
activefont = SmallFont;
hudwidth = hudheight = 0;
ClipRectLeft = ClipRectTop = ClipRectWidth = ClipRectHeight = WrapWidth = 0;
HandleAspect = true;
state = SCRIPT_Running;
// Hexen waited one second before executing any open scripts. I didn't realize

View file

@ -891,6 +891,7 @@ protected:
int hudwidth, hudheight;
int ClipRectLeft, ClipRectTop, ClipRectWidth, ClipRectHeight;
int WrapWidth;
bool HandleAspect;
FBehavior *activeBehavior;
int InModuleScriptNumber;

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

@ -2587,6 +2587,7 @@ FUNC(LS_Line_SetBlocking)
ML_BLOCKUSE,
ML_BLOCKSIGHT,
ML_BLOCKHITSCAN,
ML_SOUNDBLOCK,
-1
};

View file

@ -38,6 +38,30 @@
// TYPES -------------------------------------------------------------------
struct FGenericButtons
{
int ReadyFlag; // Flag passed to A_WeaponReady
int StateFlag; // Flag set in WeaponState
int ButtonFlag; // Button to press
ENamedName StateName; // Name of the button/state
};
enum EWRF_Options
{
WRF_NoBob = 1,
WRF_NoSwitch = 1 << 1,
WRF_NoPrimary = 1 << 2,
WRF_NoSecondary = 1 << 3,
WRF_NoFire = WRF_NoPrimary | WRF_NoSecondary,
WRF_AllowReload = 1 << 4,
WRF_AllowZoom = 1 << 5,
WRF_DisableSwitch = 1 << 6,
WRF_AllowUser1 = 1 << 7,
WRF_AllowUser2 = 1 << 8,
WRF_AllowUser3 = 1 << 9,
WRF_AllowUser4 = 1 << 10,
};
// EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
@ -57,6 +81,16 @@ CVAR(Int, sv_fastweapons, false, CVAR_SERVERINFO);
static FRandom pr_wpnreadysnd ("WpnReadySnd");
static FRandom pr_gunshot ("GunShot");
static const FGenericButtons ButtonChecks[] =
{
{ WRF_AllowZoom, WF_WEAPONZOOMOK, BT_ZOOM, NAME_Zoom },
{ WRF_AllowReload, WF_WEAPONRELOADOK, BT_RELOAD, NAME_Reload },
{ WRF_AllowUser1, WF_USER1OK, BT_USER1, NAME_User1 },
{ WRF_AllowUser2, WF_USER2OK, BT_USER2, NAME_User2 },
{ WRF_AllowUser3, WF_USER3OK, BT_USER3, NAME_User3 },
{ WRF_AllowUser4, WF_USER4OK, BT_USER4, NAME_User4 },
};
// CODE --------------------------------------------------------------------
//---------------------------------------------------------------------------
@ -95,7 +129,8 @@ void P_SetPsprite (player_t *player, int position, FState *state, bool nofunctio
if (position == ps_weapon && !nofunction)
{ // A_WeaponReady will re-set these as needed
player->WeaponState &= ~(WF_WEAPONREADY | WF_WEAPONREADYALT | WF_WEAPONBOBBING | WF_WEAPONSWITCHOK | WF_WEAPONRELOADOK | WF_WEAPONZOOMOK);
player->WeaponState &= ~(WF_WEAPONREADY | WF_WEAPONREADYALT | WF_WEAPONBOBBING | WF_WEAPONSWITCHOK | WF_WEAPONRELOADOK | WF_WEAPONZOOMOK |
WF_USER1OK | WF_USER2OK | WF_USER3OK | WF_USER4OK);
}
psp = &player->psprites[position];
@ -289,66 +324,6 @@ void P_FireWeaponAlt (player_t *player, FState *state)
}
}
//---------------------------------------------------------------------------
//
// PROC P_ReloadWeapon
//
//---------------------------------------------------------------------------
void P_ReloadWeapon (player_t *player, FState *state)
{
AWeapon *weapon;
if (player->Bot == NULL && bot_observer)
{
return;
}
weapon = player->ReadyWeapon;
if (weapon == NULL)
{
return;
}
if (state == NULL)
{
state = weapon->GetRelState();
}
// [XA] don't change state if still null, so if the modder sets
// WRF_RELOAD to true but forgets to define the Reload state, the weapon
// won't disappear. ;)
if (state != NULL)
P_SetPsprite (player, ps_weapon, state);
}
//---------------------------------------------------------------------------
//
// PROC P_ZoomWeapon
//
//---------------------------------------------------------------------------
void P_ZoomWeapon (player_t *player, FState *state)
{
AWeapon *weapon;
if (player->Bot == NULL && bot_observer)
{
return;
}
weapon = player->ReadyWeapon;
if (weapon == NULL)
{
return;
}
if (state == NULL)
{
state = weapon->GetZoomState();
}
// [XA] don't change state if still null. Same reasons as above.
if (state != NULL)
P_SetPsprite (player, ps_weapon, state);
}
//---------------------------------------------------------------------------
//
// PROC P_DropWeapon
@ -562,22 +537,21 @@ void DoReadyWeaponToBob (AActor *self)
}
}
void DoReadyWeaponToReload (AActor *self)
void DoReadyWeaponToGeneric(AActor *self, int paramflags)
{
// Prepare for reload action.
player_t *player;
if (self && (player = self->player))
player->WeaponState |= WF_WEAPONRELOADOK;
return;
}
int flags = 0;
void DoReadyWeaponToZoom (AActor *self)
{
// Prepare for reload action.
player_t *player;
if (self && (player = self->player))
player->WeaponState |= WF_WEAPONZOOMOK;
return;
for (size_t i = 0; i < countof(ButtonChecks); ++i)
{
if (paramflags & ButtonChecks[i].ReadyFlag)
{
flags |= ButtonChecks[i].StateFlag;
}
}
if (self != NULL && self->player != NULL)
{
self->player->WeaponState |= flags;
}
}
// This function replaces calls to A_WeaponReady in other codepointers.
@ -586,33 +560,18 @@ void DoReadyWeapon(AActor *self)
DoReadyWeaponToBob(self);
DoReadyWeaponToFire(self);
DoReadyWeaponToSwitch(self);
DoReadyWeaponToReload(self);
DoReadyWeaponToZoom(self);
DoReadyWeaponToGeneric(self, ~0);
}
enum EWRF_Options
{
WRF_NoBob = 1,
WRF_NoSwitch = 2,
WRF_NoPrimary = 4,
WRF_NoSecondary = 8,
WRF_NoFire = WRF_NoPrimary + WRF_NoSecondary,
WRF_AllowReload = 16,
WRF_AllowZoom = 32,
WRF_DisableSwitch = 64,
};
DEFINE_ACTION_FUNCTION_PARAMS(AInventory, A_WeaponReady)
{
PARAM_ACTION_PROLOGUE;
PARAM_INT_OPT(flags) { flags = 0; }
DoReadyWeaponToSwitch(self, !(flags & WRF_NoSwitch));
if ((flags & WRF_NoFire) != WRF_NoFire) DoReadyWeaponToFire(self, !(flags & WRF_NoPrimary), !(flags & WRF_NoSecondary));
if (!(flags & WRF_NoBob)) DoReadyWeaponToBob(self);
if ((flags & WRF_AllowReload)) DoReadyWeaponToReload(self);
if ((flags & WRF_AllowZoom)) DoReadyWeaponToZoom(self);
DoReadyWeaponToSwitch(self, !(flags & WRF_NoSwitch));
if ((flags & WRF_NoFire) != WRF_NoFire) DoReadyWeaponToFire(self, !(flags & WRF_NoPrimary), !(flags & WRF_NoSecondary));
if (!(flags & WRF_NoBob)) DoReadyWeaponToBob(self);
DoReadyWeaponToGeneric(self, flags);
DoReadyWeaponDisableSwitch(self, flags & WRF_DisableSwitch);
return 0;
}
@ -691,45 +650,40 @@ void P_CheckWeaponSwitch (player_t *player)
//---------------------------------------------------------------------------
//
// PROC P_CheckWeaponReload
// PROC P_CheckWeaponButtons
//
// The player can reload the weapon.
// Check extra button presses for weapons.
//
//---------------------------------------------------------------------------
void P_CheckWeaponReload (player_t *player)
static void P_CheckWeaponButtons (player_t *player)
{
AWeapon *weapon = player->ReadyWeapon;
if (weapon == NULL)
return;
// Check for reload.
if ((player->WeaponState & WF_WEAPONRELOADOK) && (player->cmd.ucmd.buttons & BT_RELOAD))
if (player->Bot == NULL && bot_observer)
{
P_ReloadWeapon (player, NULL);
return;
}
}
//---------------------------------------------------------------------------
//
// PROC P_CheckWeaponZoom
//
// The player can use the weapon's zoom function.
//
//---------------------------------------------------------------------------
void P_CheckWeaponZoom (player_t *player)
{
AWeapon *weapon = player->ReadyWeapon;
if (weapon == NULL)
return;
// Check for zoom.
if ((player->WeaponState & WF_WEAPONZOOMOK) && (player->cmd.ucmd.buttons & BT_ZOOM))
{
P_ZoomWeapon (player, NULL);
return;
}
// The button checks are ordered by precedence. The first one to match a
// button press and affect a state change wins.
for (size_t i = 0; i < countof(ButtonChecks); ++i)
{
if ((player->WeaponState & ButtonChecks[i].StateFlag) &&
(player->cmd.ucmd.buttons & ButtonChecks[i].ButtonFlag))
{
FState *state = weapon->GetStateForButtonName(ButtonChecks[i].StateName);
// [XA] don't change state if still null, so if the modder
// sets WRF_xxx to true but forgets to define the corresponding
// state, the weapon won't disappear. ;)
if (state != NULL)
{
P_SetPsprite(player, ps_weapon, state);
return;
}
}
}
}
@ -1126,15 +1080,10 @@ void P_MovePsprites (player_t *player)
{
P_CheckWeaponFire (player);
}
if (player->WeaponState & WF_WEAPONRELOADOK)
{
P_CheckWeaponReload (player);
// Check custom buttons
P_CheckWeaponButtons(player);
}
if (player->WeaponState & WF_WEAPONZOOMOK)
{
P_CheckWeaponZoom (player);
}
}
}
FArchive &operator<< (FArchive &arc, pspdef_t &def)

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

@ -177,10 +177,47 @@ bool P_CheckSwitchRange(AActor *user, line_t *line, int sideno)
if ((TexMan.FindSwitch(side->GetTexture(side_t::top))) != NULL)
{
// Check 3D floors on back side
{
sector_t * back = line->sidedef[1 - sideno]->sector;
for (unsigned i = 0; i < back->e->XFloor.ffloors.Size(); i++)
{
F3DFloor *rover = back->e->XFloor.ffloors[i];
if (!(rover->flags & FF_EXISTS)) continue;
if (!(rover->flags & FF_UPPERTEXTURE)) continue;
if (user->z > rover->top.plane->ZatPoint(checkx, checky) ||
user->z + user->height < rover->bottom.plane->ZatPoint(checkx, checky))
continue;
// This 3D floor depicts a switch texture in front of the player's eyes
return true;
}
}
return (user->z + user->height > open.top);
}
else if ((TexMan.FindSwitch(side->GetTexture(side_t::bottom))) != NULL)
{
// Check 3D floors on back side
{
sector_t * back = line->sidedef[1 - sideno]->sector;
for (unsigned i = 0; i < back->e->XFloor.ffloors.Size(); i++)
{
F3DFloor *rover = back->e->XFloor.ffloors[i];
if (!(rover->flags & FF_EXISTS)) continue;
if (!(rover->flags & FF_LOWERTEXTURE)) continue;
if (user->z > rover->top.plane->ZatPoint(checkx, checky) ||
user->z + user->height < rover->bottom.plane->ZatPoint(checkx, checky))
continue;
// This 3D floor depicts a switch texture in front of the player's eyes
return true;
}
}
return (user->z < open.bottom);
}
else if ((flags & ML_3DMIDTEX) || (TexMan.FindSwitch(side->GetTexture(side_t::mid))) != NULL)

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

@ -649,6 +649,10 @@ void APlayerPawn::Serialize (FArchive &arc)
{
arc << AirCapacity;
}
if (SaveVersion >= 4526)
{
arc << ViewHeight;
}
}
//===========================================================================
@ -3126,6 +3130,12 @@ void player_t::Serialize (FArchive &arc)
WeaponState = ((cheats >> 14) & 1) | ((cheats & (0x37 << 24)) >> (24 - 1));
cheats &= ~((1 << 14) | (0x37 << 24));
}
if (SaveVersion < 4527)
{
BYTE oldWeaponState;
arc << oldWeaponState;
WeaponState = oldWeaponState;
}
else
{
arc << WeaponState;

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

@ -194,14 +194,19 @@ class ASectorAction : public AActor
{
DECLARE_CLASS (ASectorAction, AActor)
public:
ASectorAction (bool activatedByUse = false);
void Destroy ();
void BeginPlay ();
void Activate (AActor *source);
void Deactivate (AActor *source);
bool TriggerAction(AActor *triggerer, int activationType);
bool CanTrigger (AActor *triggerer) const;
bool IsActivatedByUse() const;
protected:
virtual bool DoTriggerAction(AActor *triggerer, int activationType);
bool CheckTrigger(AActor *triggerer) const;
private:
bool ActivatedByUse;
};
class ASkyViewpoint;

View file

@ -1364,15 +1364,36 @@ static void S_AddSNDINFO (int lump)
case SI_MidiDevice: {
sc.MustGetString();
FName nm = sc.String;
FScanner::SavedPos save = sc.SavePos();
sc.SetCMode(true);
sc.MustGetString();
if (sc.Compare("timidity")) MidiDevices[nm] = MDEV_TIMIDITY;
else if (sc.Compare("fmod") || sc.Compare("sndsys")) MidiDevices[nm] = MDEV_SNDSYS;
else if (sc.Compare("standard")) MidiDevices[nm] = MDEV_MMAPI;
else if (sc.Compare("opl")) MidiDevices[nm] = MDEV_OPL;
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;
MidiDeviceSetting devset;
if (sc.Compare("timidity")) devset.device = MDEV_TIMIDITY;
else if (sc.Compare("fmod") || sc.Compare("sndsys")) devset.device = MDEV_SNDSYS;
else if (sc.Compare("standard")) devset.device = MDEV_MMAPI;
else if (sc.Compare("opl")) devset.device = MDEV_OPL;
else if (sc.Compare("default")) devset.device = MDEV_DEFAULT;
else if (sc.Compare("fluidsynth")) devset.device = MDEV_FLUIDSYNTH;
else if (sc.Compare("gus")) devset.device = MDEV_GUS;
else if (sc.Compare("wildmidi")) devset.device = MDEV_WILDMIDI;
else sc.ScriptError("Unknown MIDI device %s\n", sc.String);
if (sc.CheckString(","))
{
sc.SetCMode(false);
sc.MustGetString();
devset.args = sc.String;
}
else
{
// This does not really do what one might expect, because the next token has already been parsed and can be a '$'.
// So in order to continue parsing without C-Mode, we need to reset and parse the last token again.
sc.SetCMode(false);
sc.RestorePos(save);
sc.MustGetString();
}
MidiDevices[nm] = devset;
}
break;

View file

@ -2421,11 +2421,8 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
{
int lumpnum = -1;
int length = 0;
int device = MDEV_DEFAULT;
MusInfo *handle = NULL;
int *devp = MidiDevices.CheckKey(musicname);
if (devp != NULL) device = *devp;
MidiDeviceSetting *devp = MidiDevices.CheckKey(musicname);
// Strip off any leading file:// component.
if (strncmp(musicname, "file://", 7) == 0)
@ -2495,7 +2492,7 @@ bool S_ChangeMusic (const char *musicname, int order, bool looping, bool force)
}
else
{
mus_playing.handle = I_RegisterSong (reader, device);
mus_playing.handle = I_RegisterSong (reader, devp);
}
}

View file

@ -394,10 +394,22 @@ enum EMidiDevice
MDEV_TIMIDITY = 3,
MDEV_FLUIDSYNTH = 4,
MDEV_GUS = 5,
MDEV_WILDMIDI = 6,
};
struct MidiDeviceSetting
{
int device;
FString args;
MidiDeviceSetting()
{
device = MDEV_DEFAULT;
}
};
typedef TMap<FName, FName> MusicAliasMap;
typedef TMap<FName, int> MidiDeviceMap;
typedef TMap<FName, MidiDeviceSetting> MidiDeviceMap;
extern MusicAliasMap MusicAliases;
extern MidiDeviceMap MidiDevices;

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";
@ -301,21 +311,21 @@ MusInfo *MusInfo::GetWaveDumper(const char *filename, int rate)
//
//==========================================================================
static MIDIStreamer *CreateMIDIStreamer(FileReader &reader, EMidiDevice devtype, EMIDIType miditype)
static MIDIStreamer *CreateMIDIStreamer(FileReader &reader, EMidiDevice devtype, EMIDIType miditype, const char *args)
{
switch (miditype)
{
case MIDI_MUS:
return new MUSSong2(reader, devtype);
return new MUSSong2(reader, devtype, args);
case MIDI_MIDI:
return new MIDISong2(reader, devtype);
return new MIDISong2(reader, devtype, args);
case MIDI_HMI:
return new HMISong(reader, devtype);
return new HMISong(reader, devtype, args);
case MIDI_XMI:
return new XMISong(reader, devtype);
return new XMISong(reader, devtype, args);
default:
return NULL;
@ -377,7 +387,7 @@ static EMIDIType IdentifyMIDIType(DWORD *id, int size)
//
//==========================================================================
MusInfo *I_RegisterSong (FileReader *reader, int device)
MusInfo *I_RegisterSong (FileReader *reader, MidiDeviceSetting *device)
{
MusInfo *info = NULL;
const char *fmt;
@ -395,12 +405,6 @@ MusInfo *I_RegisterSong (FileReader *reader, int device)
return 0;
}
#ifndef _WIN32
// non-Windows platforms don't support MDEV_MMAPI so map to MDEV_SNDSYS
if (device == MDEV_MMAPI)
device = MDEV_SNDSYS;
#endif
// Check for gzip compression. Some formats are expected to have players
// that can handle it, so it simplifies things if we make all songs
// gzippable.
@ -437,10 +441,15 @@ MusInfo *I_RegisterSong (FileReader *reader, int device)
EMIDIType miditype = IdentifyMIDIType(id, sizeof(id));
if (miditype != MIDI_NOTMIDI)
{
EMidiDevice devtype = (EMidiDevice)device;
EMidiDevice devtype = device == NULL? MDEV_DEFAULT : (EMidiDevice)device->device;
#ifndef _WIN32
// non-Windows platforms don't support MDEV_MMAPI so map to MDEV_SNDSYS
if (devtype == MDEV_MMAPI)
devtype = MDEV_SNDSYS;
#endif
retry_as_sndsys:
info = CreateMIDIStreamer(*reader, devtype, miditype);
info = CreateMIDIStreamer(*reader, devtype, miditype, device != NULL? device->args.GetChars() : "");
if (info != NULL && !info->IsValid())
{
delete info;
@ -454,7 +463,7 @@ retry_as_sndsys:
#ifdef _WIN32
if (info == NULL && devtype != MDEV_MMAPI && snd_mididevice >= 0)
{
info = CreateMIDIStreamer(*reader, MDEV_MMAPI, miditype);
info = CreateMIDIStreamer(*reader, MDEV_MMAPI, miditype, "");
}
#endif
}
@ -465,7 +474,7 @@ retry_as_sndsys:
(id[0] == MAKE_ID('D','B','R','A') && id[1] == MAKE_ID('W','O','P','L')) || // DosBox Raw OPL
(id[0] == MAKE_ID('A','D','L','I') && *((BYTE *)id + 4) == 'B')) // Martin Fernandez's modified IMF
{
info = new OPLMUSSong (*reader);
info = new OPLMUSSong (*reader, device != NULL? device->args.GetChars() : "");
}
// Check for game music
else if ((fmt = GME_CheckFormat(id[0])) != NULL && fmt[0] != '\0')

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 ();
@ -52,7 +53,8 @@ void I_SetMusicVolume (float volume);
// Registers a song handle to song data.
class MusInfo;
MusInfo *I_RegisterSong (FileReader *reader, int device);
struct MidiDeviceSetting;
MusInfo *I_RegisterSong (FileReader *reader, MidiDeviceSetting *device);
MusInfo *I_RegisterCDSong (int track, int cdid = 0);
MusInfo *I_RegisterURLSong (const char *url);
@ -81,6 +83,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();
};
@ -183,7 +185,7 @@ public:
class TimidityPPMIDIDevice : public PseudoMIDIDevice
{
public:
TimidityPPMIDIDevice();
TimidityPPMIDIDevice(const char *args);
~TimidityPPMIDIDevice();
int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
@ -218,7 +220,6 @@ protected:
#endif
};
// Base class for software synthesizer MIDI output devices ------------------
class SoftSynthMIDIDevice : public MIDIDevice
@ -269,7 +270,7 @@ protected:
class OPLMIDIDevice : public SoftSynthMIDIDevice, protected OPLmusicBlock
{
public:
OPLMIDIDevice();
OPLMIDIDevice(const char *args);
int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
void Close();
int GetTechnology() const;
@ -302,7 +303,7 @@ namespace Timidity { struct Renderer; }
class TimidityMIDIDevice : public SoftSynthMIDIDevice
{
public:
TimidityMIDIDevice();
TimidityMIDIDevice(const char *args);
~TimidityMIDIDevice();
int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
@ -331,6 +332,27 @@ protected:
FILE *File;
};
// WildMidi implementation of a MIDI device ---------------------------------
class WildMIDIDevice : public SoftSynthMIDIDevice
{
public:
WildMIDIDevice(const char *args);
~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
@ -344,7 +366,7 @@ struct fluid_synth_t;
class FluidSynthMIDIDevice : public SoftSynthMIDIDevice
{
public:
FluidSynthMIDIDevice();
FluidSynthMIDIDevice(const char *args);
~FluidSynthMIDIDevice();
int Open(void (*callback)(unsigned int, void *, DWORD, DWORD), void *userdata);
@ -409,7 +431,7 @@ protected:
class MIDIStreamer : public MusInfo
{
public:
MIDIStreamer(EMidiDevice type);
MIDIStreamer(EMidiDevice type, const char *args);
~MIDIStreamer();
void MusicVolumeChanged();
@ -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:
@ -494,6 +517,7 @@ protected:
bool CallbackIsThreaded;
int LoopLimit;
FString DumpFilename;
FString Args;
};
// MUS file played with a MIDI stream ---------------------------------------
@ -501,7 +525,7 @@ protected:
class MUSSong2 : public MIDIStreamer
{
public:
MUSSong2(FileReader &reader, EMidiDevice type);
MUSSong2(FileReader &reader, EMidiDevice type, const char *args);
~MUSSong2();
MusInfo *GetOPLDumper(const char *filename);
@ -527,7 +551,7 @@ protected:
class MIDISong2 : public MIDIStreamer
{
public:
MIDISong2(FileReader &reader, EMidiDevice type);
MIDISong2(FileReader &reader, EMidiDevice type, const char *args);
~MIDISong2();
MusInfo *GetOPLDumper(const char *filename);
@ -546,7 +570,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;
@ -584,7 +608,7 @@ protected:
class HMISong : public MIDIStreamer
{
public:
HMISong(FileReader &reader, EMidiDevice type);
HMISong(FileReader &reader, EMidiDevice type, const char *args);
~HMISong();
MusInfo *GetOPLDumper(const char *filename);
@ -627,7 +651,7 @@ protected:
class XMISong : public MIDIStreamer
{
public:
XMISong(FileReader &reader, EMidiDevice type);
XMISong(FileReader &reader, EMidiDevice type, const char *args);
~XMISong();
MusInfo *GetOPLDumper(const char *filename);
@ -690,7 +714,7 @@ protected:
class OPLMUSSong : public StreamSong
{
public:
OPLMUSSong (FileReader &reader);
OPLMUSSong (FileReader &reader, const char *args);
~OPLMUSSong ();
void Play (bool looping, int subsong);
bool IsPlaying ();

View file

@ -255,7 +255,7 @@ CUSTOM_CVAR(Int, fluid_chorus_type, FLUID_CHORUS_DEFAULT_TYPE, CVAR_ARCHIVE|CVAR
//
//==========================================================================
FluidSynthMIDIDevice::FluidSynthMIDIDevice()
FluidSynthMIDIDevice::FluidSynthMIDIDevice(const char *args)
{
FluidSynth = NULL;
FluidSettings = NULL;
@ -293,7 +293,15 @@ FluidSynthMIDIDevice::FluidSynthMIDIDevice()
fluid_reverb_width, fluid_reverb_level);
fluid_synth_set_chorus(FluidSynth, fluid_chorus_voices, fluid_chorus_level,
fluid_chorus_speed, fluid_chorus_depth, fluid_chorus_type);
if (0 == LoadPatchSets(fluid_patchset))
// try loading a patch set that got specified with $mididevice.
int res = 0;
if (args != NULL && *args != 0)
{
res = LoadPatchSets(args);
}
if (res == 0 && 0 == LoadPatchSets(fluid_patchset))
{
#ifdef __unix__
// This is the standard location on Ubuntu.

View file

@ -128,8 +128,8 @@ extern char MIDI_CommonLengths[15];
//
//==========================================================================
HMISong::HMISong (FileReader &reader, EMidiDevice type)
: MIDIStreamer(type), MusHeader(0), Tracks(0)
HMISong::HMISong (FileReader &reader, EMidiDevice type, const char *args)
: MIDIStreamer(type, args), MusHeader(0), Tracks(0)
{
#ifdef _WIN32
if (ExitEvent == NULL)

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

@ -72,7 +72,7 @@ CUSTOM_CVAR (Int, timidity_frequency, 22050, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
//
//==========================================================================
TimidityPPMIDIDevice::TimidityPPMIDIDevice()
TimidityPPMIDIDevice::TimidityPPMIDIDevice(const char *args)
: DiskName("zmid"),
#ifdef _WIN32
ReadWavePipe(INVALID_HANDLE_VALUE), WriteWavePipe(INVALID_HANDLE_VALUE),
@ -86,6 +86,12 @@ TimidityPPMIDIDevice::TimidityPPMIDIDevice()
WavePipe[0] = WavePipe[1] = -1;
#endif
if (args == NULL || *args == 0) args = timidity_exe;
CommandLine.Format("%s %s -EFchorus=%s -EFreverb=%s -s%d ",
args, *timidity_extargs,
*timidity_chorus, *timidity_reverb, *timidity_frequency);
if (DiskName == NULL)
{
Printf(PRINT_BOLD, "Could not create temp music file\n");
@ -187,10 +193,6 @@ int TimidityPPMIDIDevice::Open(void (*callback)(unsigned int, void *, DWORD, DWO
Validated = true;
#endif // WIN32
CommandLine.Format("%s %s -EFchorus=%s -EFreverb=%s -s%d ",
*timidity_exe, *timidity_extargs,
*timidity_chorus, *timidity_reverb, *timidity_frequency);
pipeSize = (timidity_pipe * timidity_frequency / 1000)
<< (timidity_stereo + !timidity_8bit);

View file

@ -89,12 +89,12 @@ static const BYTE StaticMIDIhead[] =
//
//==========================================================================
MIDIStreamer::MIDIStreamer(EMidiDevice type)
MIDIStreamer::MIDIStreamer(EMidiDevice type, const char *args)
:
#ifdef _WIN32
PlayerThread(0), ExitEvent(0), BufferDoneEvent(0),
#endif
MIDI(0), Division(0), InitialTempo(500000), DeviceType(type)
MIDI(0), Division(0), InitialTempo(500000), DeviceType(type), Args(args)
{
#ifdef _WIN32
BufferDoneEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
@ -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;
@ -268,19 +269,19 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const
#ifdef HAVE_FLUIDSYNTH
case MDEV_FLUIDSYNTH:
return new FluidSynthMIDIDevice;
return new FluidSynthMIDIDevice(Args);
#endif
case MDEV_SNDSYS:
return new SndSysMIDIDevice;
case MDEV_GUS:
return new TimidityMIDIDevice;
return new TimidityMIDIDevice(Args);
case MDEV_OPL:
try
{
return new OPLMIDIDevice;
return new OPLMIDIDevice(Args);
}
catch (CRecoverableError &err)
{
@ -290,7 +291,10 @@ MIDIDevice *MIDIStreamer::CreateMIDIDevice(EMidiDevice devtype) const
}
case MDEV_TIMIDITY:
return new TimidityPPMIDIDevice;
return new TimidityPPMIDIDevice(Args);
case MDEV_WILDMIDI:
return new WildMIDIDevice(Args);
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

@ -43,6 +43,7 @@
#include "doomdef.h"
#include "m_swap.h"
#include "files.h"
#include "s_sound.h"
// MACROS ------------------------------------------------------------------
@ -92,8 +93,8 @@ static const BYTE CtrlTranslate[15] =
//
//==========================================================================
MUSSong2::MUSSong2 (FileReader &reader, EMidiDevice type)
: MIDIStreamer(type), MusHeader(0), MusBuffer(0)
MUSSong2::MUSSong2 (FileReader &reader, EMidiDevice type, const char *args)
: MIDIStreamer(type, args), MusHeader(0), MusBuffer(0)
{
#ifdef _WIN32
if (ExitEvent == NULL)
@ -210,23 +211,44 @@ bool MUSSong2::CheckDone()
void MUSSong2::Precache()
{
WORD *work = (WORD *)alloca(MusHeader->NumInstruments * sizeof(WORD));
const WORD *used = (WORD *)MusHeader + sizeof(MUSHeader) / sizeof(WORD);
int i, j;
TArray<WORD> work(MusHeader->NumInstruments);
const BYTE *used = (BYTE *)MusHeader + sizeof(MUSHeader) / sizeof(BYTE);
int i, k;
for (i = j = 0; i < MusHeader->NumInstruments; ++i)
for (i = k = 0; i < MusHeader->NumInstruments; ++i)
{
WORD instr = LittleShort(used[i]);
BYTE instr = used[k++];
WORD val;
if (instr < 128)
{
work[j++] = instr;
val = instr;
}
else if (used[i] >= 135 && used[i] <= 181)
else if (instr >= 135 && instr <= 188)
{ // Percussions are 100-based, not 128-based, eh?
work[j++] = instr - 100 + (1 << 14);
val = instr - 100 + (1 << 14);
}
else
{
// skip it.
val = used[k++];
k += val;
continue;
}
int numbanks = used[k++];
if (numbanks > 0)
{
for (int b = 0; b < numbanks; b++)
{
work.Push(val | (used[k++] << 7));
}
}
else
{
work.Push(val);
}
}
MIDI->PrecacheInstruments(&work[0], j);
MIDI->PrecacheInstruments(&work[0], work.Size());
}
//==========================================================================

View file

@ -20,16 +20,25 @@ CUSTOM_CVAR (Int, opl_numchips, 2, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
}
}
CVAR(Int, opl_core, 0, CVAR_ARCHIVE|CVAR_GLOBALCONFIG)
CVAR(Int, opl_core, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
int current_opl_core;
OPLMUSSong::OPLMUSSong (FileReader &reader)
// Get OPL core override from $mididevice
void OPL_SetCore(const char *args)
{
current_opl_core = opl_core;
if (args != NULL && *args >= '0' && *args < '4') current_opl_core = *args - '0';
}
OPLMUSSong::OPLMUSSong (FileReader &reader, const char *args)
{
int samples = int(OPL_SAMPLE_RATE / 14);
OPL_SetCore(args);
Music = new OPLmusicFile (&reader);
m_Stream = GSnd->CreateStream (FillStream, samples*4,
(opl_core == 0 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this);
(current_opl_core == 0 ? SoundStream::Mono : 0) | SoundStream::Float, int(OPL_SAMPLE_RATE), this);
if (m_Stream == NULL)
{
Printf (PRINT_BOLD, "Could not create music stream.\n");

View file

@ -102,8 +102,8 @@ char MIDI_CommonLengths[15] = { 0, 1, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
//
//==========================================================================
MIDISong2::MIDISong2 (FileReader &reader, EMidiDevice type)
: MIDIStreamer(type), MusHeader(0), Tracks(0)
MIDISong2::MIDISong2 (FileReader &reader, EMidiDevice type, const char *args)
: MIDIStreamer(type, args), MusHeader(0), Tracks(0)
{
int p;
int i;
@ -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

@ -86,10 +86,10 @@ struct FmtChunk
//
//==========================================================================
TimidityMIDIDevice::TimidityMIDIDevice()
TimidityMIDIDevice::TimidityMIDIDevice(const char *args)
{
Renderer = NULL;
Renderer = new Timidity::Renderer((float)SampleRate);
Renderer = new Timidity::Renderer((float)SampleRate, args);
}
//==========================================================================
@ -245,6 +245,7 @@ FString TimidityMIDIDevice::GetStats()
//==========================================================================
TimidityWaveWriterMIDIDevice::TimidityWaveWriterMIDIDevice(const char *filename, int rate)
:TimidityMIDIDevice(NULL)
{
File = fopen(filename, "wb");
if (File != NULL)

View file

@ -0,0 +1,234 @@
/*
** 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(const char *args)
{
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 (args == NULL || *args == 0) args = wildmidi_config;
if (CurrentConfig.CompareNoCase(args) != 0 || SampleRate != WildMidi_GetSampleRate())
{
if (CurrentConfig.IsNotEmpty())
{
WildMidi_Shutdown();
CurrentConfig = "";
}
if (!WildMidi_Init(args, SampleRate, 0))
{
CurrentConfig = args;
}
}
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

@ -108,8 +108,8 @@ extern char MIDI_CommonLengths[15];
//
//==========================================================================
XMISong::XMISong (FileReader &reader, EMidiDevice type)
: MIDIStreamer(type), MusHeader(0), Songs(0)
XMISong::XMISong (FileReader &reader, EMidiDevice type, const char *args)
: MIDIStreamer(type, args), MusHeader(0), Songs(0)
{
#ifdef _WIN32
if (ExitEvent == NULL)

View file

@ -1246,7 +1246,8 @@ void FTextureManager::PrecacheLevel (void)
for (unsigned i = 0; i < level.info->PrecacheTextures.Size(); i++)
{
hitlist[level.info->PrecacheTextures[i].GetIndex()] |= FTextureManager::HIT_Wall;
FTextureID tex = TexMan.CheckForTexture(level.info->PrecacheTextures[i], FTexture::TEX_Wall, FTextureManager::TEXMAN_Overridable|FTextureManager::TEXMAN_TryAny|FTextureManager::TEXMAN_ReturnFirst);
if (tex.Exists()) hitlist[tex.GetIndex()] |= FTextureManager::HIT_Wall;
}
for (int i = cnt - 1; i >= 0; i--)

View file

@ -6263,6 +6263,104 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetRipMax)
return 0;
}
//==========================================================================
//
// A_CheckProximity(jump, classname, distance, count, flags, ptr)
//
// Checks to see if a certain actor class is close to the
// actor/pointer within distance, in numbers.
//==========================================================================
enum CPXFflags
{
CPXF_ANCESTOR = 1,
CPXF_LESSOREQUAL = 1 << 1,
CPXF_NOZ = 1 << 2,
CPXF_COUNTDEAD = 1 << 3,
CPXF_DEADONLY = 1 << 4,
CPXF_EXACT = 1 << 5,
};
DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_CheckProximity)
{
PARAM_ACTION_PROLOGUE;
PARAM_STATE(jump);
PARAM_CLASS(classname, AActor);
PARAM_FIXED(distance);
PARAM_INT_OPT(count) { count = 1; }
PARAM_INT(flags) { flags = 0; }
PARAM_INT(ptr) { ptr = AAPTR_DEFAULT; }
ACTION_SET_RESULT(false); //No inventory chain results please.
AActor *ref = COPY_AAPTR(self, ptr);
//We need these to check out.
if (!ref || !jump || !classname || distance <= 0)
return numret;
int counter = 0;
bool result = false;
TThinkerIterator<AActor> it;
AActor * mo;
//[MC] Process of elimination, I think, will get through this as quickly and
//efficiently as possible.
while ((mo = it.Next()))
{
if (mo == ref) //Don't count self.
continue;
//Check inheritance for the classname. Taken partly from CheckClass DECORATE function.
if (flags & CPXF_ANCESTOR)
{
if (!(mo->GetClass()->IsAncestorOf(classname)))
continue;
}
//Otherwise, just check for the regular class name.
else if (classname != mo->GetClass())
continue;
//Make sure it's in range and respect the desire for Z or not.
if (P_AproxDistance(ref->x - mo->x, ref->y - mo->y) < distance &&
((flags & CPXF_NOZ) ||
((ref->z > mo->z && ref->z - (mo->z + mo->height) < distance) ||
(ref->z <= mo->z && mo->z - (ref->z + ref->height) < distance))))
{
if (mo->flags6 & MF6_KILLED)
{
if (!(flags & (CPXF_COUNTDEAD | CPXF_DEADONLY)))
continue;
counter++;
}
else
{
if (flags & CPXF_DEADONLY)
continue;
counter++;
}
//Abort if the number of matching classes nearby is greater, we have obviously succeeded in our goal.
if (counter > count)
{
result = (flags & (CPXF_LESSOREQUAL | CPXF_EXACT)) ? false : true;
break;
}
}
}
if (counter == count)
result = true;
else if (counter < count)
result = !!((flags & CPXF_LESSOREQUAL) && !(flags & CPXF_EXACT));
if (result)
{
ACTION_JUMP(jump);
}
return numret;
}
/*===========================================================================
A_CheckBlock
(state block, int flags, int ptr)

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;
@ -686,8 +678,9 @@ int LoadDMXGUS()
return 0;
}
Renderer::Renderer(float sample_rate)
Renderer::Renderer(float sample_rate, const char *args)
{
// 'args' should be used to load a custom config or DMXGUS, but since setup currently requires a snd_reset call, this will need some refactoring first
rate = sample_rate;
patches = NULL;
resample_buffer_size = 0;

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];
@ -647,7 +630,7 @@ struct Renderer
int voices;
int lost_notes, cut_notes;
Renderer(float sample_rate);
Renderer(float sample_rate, const char *args);
~Renderer();
void HandleEvent(int status, int parm1, int parm2);

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 4524
#define SAVEVER 4527
#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

@ -1726,3 +1726,36 @@ FString I_GetLongPathName(FString shortpath)
delete[] buff;
return longpath;
}
#if _MSC_VER == 1900 && defined(_USING_V110_SDK71_)
//==========================================================================
//
// VS14Stat
//
// Work around an issue where stat doesn't work with v140_xp. This was
// supposedly fixed, but as of Update 1 continues to not function on XP.
//
//==========================================================================
#include <sys/stat.h>
int VS14Stat(const char *path, struct _stat64i32 *buffer)
{
WIN32_FILE_ATTRIBUTE_DATA data;
if(!GetFileAttributesEx(path, GetFileExInfoStandard, &data))
return -1;
buffer->st_ino = 0;
buffer->st_mode = ((data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR : S_IFREG)|
((data.dwFileAttributes & FILE_ATTRIBUTE_READONLY) ? S_IREAD : S_IREAD|S_IWRITE);
buffer->st_dev = buffer->st_rdev = 0;
buffer->st_nlink = 1;
buffer->st_uid = 0;
buffer->st_gid = 0;
buffer->st_size = data.nFileSizeLow;
buffer->st_atime = (*(QWORD*)&data.ftLastAccessTime) / 10000000 - 11644473600LL;
buffer->st_mtime = (*(QWORD*)&data.ftLastWriteTime) / 10000000 - 11644473600LL;
buffer->st_ctime = (*(QWORD*)&data.ftCreationTime) / 10000000 - 11644473600LL;
return 0;
}
#endif

View file

@ -3105,6 +3105,7 @@ struct lemon *lemp;
FILE *in;
char *tpltname;
char *cp;
Boolean tpltnameinbuf;
cp = strrchr(lemp->filename,'.');
if( cp ){
@ -3114,10 +3115,13 @@ struct lemon *lemp;
}
if( access(buf,004)==0 ){
tpltname = buf;
tpltnameinbuf = LEMON_TRUE;
}else if( access(templatename,004)==0 ){
tpltname = templatename;
tpltnameinbuf = LEMON_TRUE;
}else{
tpltname = pathsearch(lemp->argv0,templatename,0);
tpltnameinbuf = LEMON_FALSE;
}
if( tpltname==0 ){
fprintf(stderr,"Can't find the parser driver template file \"%s\".\n",
@ -3128,11 +3132,11 @@ struct lemon *lemp;
in = fopen(tpltname,"rb");
if( in==0 ){
fprintf(stderr,"Can't open the template file \"%s\".\n",templatename);
free(tpltname);
if (tpltnameinbuf == LEMON_FALSE) free(tpltname);
lemp->errorcnt++;
return 0;
}
free(tpltname);
if (tpltnameinbuf == LEMON_FALSE) free(tpltname);
return in;
}

View file

@ -305,6 +305,7 @@ ACTOR Actor native //: Thinker
action native A_SetRipperLevel(int level);
action native A_SetRipMin(int min);
action native A_SetRipMax(int max);
action native A_CheckProximity(state jump, class<Actor> classname, float distance, int count = 1, int flags = 0, int ptr = AAPTR_DEFAULT);
action native A_CheckBlock(state block, int flags = 0, int ptr = AAPTR_DEFAULT);
action native A_CheckSightOrRange(float distance, state label, bool two_dimension = false);
action native A_CheckRange(float distance, state label, bool two_dimension = false);

View file

@ -129,6 +129,10 @@ const int WRF_NOFIRE = WRF_NOPRIMARY | WRF_NOSECONDARY;
const int WRF_ALLOWRELOAD = 16;
const int WRF_ALLOWZOOM = 32;
const int WRF_DISABLESWITCH = 64;
const int WRF_ALLOWUSER1 = 128;
const int WRF_ALLOWUSER2 = 256;
const int WRF_ALLOWUSER3 = 512;
const int WRF_ALLOWUSER4 = 1024;
// Morph constants
const int MRF_ADDSTAMINA = 1;
@ -484,6 +488,17 @@ enum
QF_WAVE = 1 << 5,
};
// A_CheckProximity flags
enum
{
CPXF_ANCESTOR = 1,
CPXF_LESSOREQUAL = 1 << 1,
CPXF_NOZ = 1 << 2,
CPXF_COUNTDEAD = 1 << 3,
CPXF_DEADONLY = 1 << 4,
CPXF_EXACT = 1 << 5,
};
// Flags for A_CheckBlock
// These flags only affect the calling actor('s pointer), not the ones being searched.
enum

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

@ -435,8 +435,12 @@ OptionMenu "CustomizeControls"
StaticText "Controls", 1
Control "Fire", "+attack"
Control "Secondary Fire", "+altattack"
Control "Weapon Reload", "+reload"
Control "Weapon Zoom", "+zoom"
Control "Weapon Reload", "+reload"
Control "Weapon Zoom", "+zoom"
Control "Weapon State 1", "+user1"
Control "Weapon State 2", "+user2"
Control "Weapon State 3", "+user3"
Control "Weapon State 4", "+user4"
Control "Use / Open", "+use"
Control "Move forward", "+forward"
Control "Move backward", "+back"
@ -1592,7 +1596,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 " "
@ -1608,6 +1611,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

@ -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"