mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-29 15:12:11 +00:00
This commit is contained in:
commit
d760b5070a
18 changed files with 595 additions and 530 deletions
|
@ -2012,8 +2012,8 @@ PDynArray::PDynArray()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
PDynArray::PDynArray(PType *etype)
|
||||
: ElementType(etype)
|
||||
PDynArray::PDynArray(PType *etype,PStruct *backing)
|
||||
: ElementType(etype), BackingType(backing)
|
||||
{
|
||||
mDescriptiveName.Format("DynArray<%s>", etype->DescriptiveName());
|
||||
Size = sizeof(FArray);
|
||||
|
@ -2061,7 +2061,33 @@ PDynArray *NewDynArray(PType *type)
|
|||
PType *atype = TypeTable.FindType(RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, &bucket);
|
||||
if (atype == NULL)
|
||||
{
|
||||
atype = new PDynArray(type);
|
||||
FString backingname;
|
||||
|
||||
switch (type->GetRegType())
|
||||
{
|
||||
case REGT_INT:
|
||||
backingname.Format("DynArray_I%d", type->Size * 8);
|
||||
break;
|
||||
|
||||
case REGT_FLOAT:
|
||||
backingname.Format("DynArray_F%d", type->Size * 8);
|
||||
break;
|
||||
|
||||
case REGT_STRING:
|
||||
backingname = "DynArray_String";
|
||||
break;
|
||||
|
||||
case REGT_POINTER:
|
||||
backingname = "DynArray_Ptr";
|
||||
break;
|
||||
|
||||
default:
|
||||
I_Error("Unsupported dynamic array requested");
|
||||
break;
|
||||
}
|
||||
|
||||
auto backing = NewNativeStruct(backingname, nullptr);
|
||||
atype = new PDynArray(type, backing);
|
||||
TypeTable.AddType(atype, RUNTIME_CLASS(PDynArray), (intptr_t)type, 0, bucket);
|
||||
}
|
||||
return (PDynArray *)atype;
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#endif
|
||||
|
||||
typedef std::pair<const class PType *, unsigned> FTypeAndOffset;
|
||||
class PStruct;
|
||||
|
||||
#include "vm.h"
|
||||
|
||||
|
@ -649,9 +650,10 @@ class PDynArray : public PCompoundType
|
|||
DECLARE_CLASS(PDynArray, PCompoundType);
|
||||
HAS_OBJECT_POINTERS;
|
||||
public:
|
||||
PDynArray(PType *etype);
|
||||
PDynArray(PType *etype, PStruct *backing);
|
||||
|
||||
PType *ElementType;
|
||||
PStruct *BackingType;
|
||||
|
||||
virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
|
||||
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
|
||||
|
|
|
@ -821,6 +821,8 @@ xx(DamageFunction)
|
|||
xx(Length)
|
||||
xx(Unit)
|
||||
xx(Size)
|
||||
xx(Copy)
|
||||
xx(Move)
|
||||
xx(Voidptr)
|
||||
xx(StateLabel)
|
||||
xx(SpriteID)
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Name: General Use Types Definitions -- Header Include file
|
||||
* Version: 1.24
|
||||
* Author: Vladimir Arnost (QA-Software)
|
||||
* Last revision: Sep-4-1995
|
||||
* Compiler: Borland C++ 3.1, Watcom C/C++ 10.0
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DEFTYPES_H_
|
||||
#define __DEFTYPES_H_
|
||||
|
||||
/* Global type declarations */
|
||||
|
||||
#include "doomtype.h"
|
||||
|
||||
/* machine dependent types */
|
||||
typedef unsigned char uchar;
|
||||
typedef unsigned short ushort;
|
||||
typedef unsigned int uint;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
typedef signed char schar;
|
||||
typedef signed short sshort;
|
||||
typedef signed int sint;
|
||||
typedef signed long slong;
|
||||
|
||||
#endif // __DEFTYPES_H_
|
|
@ -105,12 +105,6 @@ Revision History:
|
|||
/* compiler dependence */
|
||||
#ifndef OSD_CPU_H
|
||||
#define OSD_CPU_H
|
||||
typedef unsigned char UINT8; /* unsigned 8bit */
|
||||
typedef unsigned short UINT16; /* unsigned 16bit */
|
||||
typedef unsigned int UINT32; /* unsigned 32bit */
|
||||
typedef signed char INT8; /* signed 8bit */
|
||||
typedef signed short INT16; /* signed 16bit */
|
||||
typedef signed int INT32; /* signed 32bit */
|
||||
#endif
|
||||
|
||||
#ifndef PI
|
||||
|
@ -119,34 +113,30 @@ typedef signed int INT32; /* signed 32bit */
|
|||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (disable: 4244)
|
||||
#define INLINE __forceinline
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define INLINE __inline
|
||||
#endif
|
||||
|
||||
#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
|
||||
#define EG_SH 16 /* 16.16 fixed point (EG timing) */
|
||||
#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */
|
||||
#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */
|
||||
#define FREQ_SH 16 /* 16.16 fixed point (frequency calculations) */
|
||||
#define EG_SH 16 /* 16.16 fixed point (EG timing) */
|
||||
#define LFO_SH 24 /* 8.24 fixed point (LFO calculations) */
|
||||
#define TIMER_SH 16 /* 16.16 fixed point (timers calculations) */
|
||||
|
||||
#define FREQ_MASK ((1<<FREQ_SH)-1)
|
||||
#define FREQ_MASK ((1<<FREQ_SH)-1)
|
||||
|
||||
/* envelope output entries */
|
||||
#define ENV_BITS 10
|
||||
#define ENV_LEN (1<<ENV_BITS)
|
||||
#define ENV_STEP (128.0/ENV_LEN)
|
||||
#define ENV_BITS 10
|
||||
#define ENV_LEN (1<<ENV_BITS)
|
||||
#define ENV_STEP (128.0/ENV_LEN)
|
||||
|
||||
#define MAX_ATT_INDEX ((1<<(ENV_BITS-1))-1) /*511*/
|
||||
#define MIN_ATT_INDEX (0)
|
||||
#define MAX_ATT_INDEX ((1<<(ENV_BITS-1))-1) /*511*/
|
||||
#define MIN_ATT_INDEX (0)
|
||||
|
||||
/* sinwave entries */
|
||||
#define SIN_BITS 10
|
||||
#define SIN_LEN (1<<SIN_BITS)
|
||||
#define SIN_MASK (SIN_LEN-1)
|
||||
#define SIN_BITS 10
|
||||
#define SIN_LEN (1<<SIN_BITS)
|
||||
#define SIN_MASK (SIN_LEN-1)
|
||||
|
||||
#define TL_RES_LEN (256) /* 8 bits addressing (real chip) */
|
||||
#define TL_RES_LEN (256) /* 8 bits addressing (real chip) */
|
||||
|
||||
|
||||
|
||||
|
@ -156,11 +146,11 @@ typedef signed int INT32; /* signed 32bit */
|
|||
|
||||
/* Envelope Generator phases */
|
||||
|
||||
#define EG_ATT 4
|
||||
#define EG_DEC 3
|
||||
#define EG_SUS 2
|
||||
#define EG_REL 1
|
||||
#define EG_OFF 0
|
||||
#define EG_ATT 4
|
||||
#define EG_DEC 3
|
||||
#define EG_SUS 2
|
||||
#define EG_REL 1
|
||||
#define EG_OFF 0
|
||||
|
||||
|
||||
#define OPL_CLOCK 3579545 // master clock (Hz)
|
||||
|
@ -171,97 +161,100 @@ typedef signed int INT32; /* signed 32bit */
|
|||
|
||||
/* Saving is necessary for member of the 'R' mark for suspend/resume */
|
||||
|
||||
typedef struct{
|
||||
UINT32 ar; /* attack rate: AR<<2 */
|
||||
UINT32 dr; /* decay rate: DR<<2 */
|
||||
UINT32 rr; /* release rate:RR<<2 */
|
||||
UINT8 KSR; /* key scale rate */
|
||||
UINT8 ksl; /* keyscale level */
|
||||
UINT8 ksr; /* key scale rate: kcode>>KSR */
|
||||
UINT8 mul; /* multiple: mul_tab[ML] */
|
||||
struct OPL_SLOT
|
||||
{
|
||||
uint32_t ar; /* attack rate: AR<<2 */
|
||||
uint32_t dr; /* decay rate: DR<<2 */
|
||||
uint32_t rr; /* release rate:RR<<2 */
|
||||
uint8_t KSR; /* key scale rate */
|
||||
uint8_t ksl; /* keyscale level */
|
||||
uint8_t ksr; /* key scale rate: kcode>>KSR */
|
||||
uint8_t mul; /* multiple: mul_tab[ML] */
|
||||
|
||||
/* Phase Generator */
|
||||
UINT32 Cnt; /* frequency counter */
|
||||
UINT32 Incr; /* frequency counter step */
|
||||
UINT8 FB; /* feedback shift value */
|
||||
INT32 *connect1; /* slot1 output pointer */
|
||||
INT32 op1_out[2]; /* slot1 output for feedback */
|
||||
UINT8 CON; /* connection (algorithm) type */
|
||||
uint32_t Cnt; /* frequency counter */
|
||||
uint32_t Incr; /* frequency counter step */
|
||||
uint8_t FB; /* feedback shift value */
|
||||
int32_t *connect1; /* slot1 output pointer */
|
||||
int32_t op1_out[2]; /* slot1 output for feedback */
|
||||
uint8_t CON; /* connection (algorithm) type */
|
||||
|
||||
/* Envelope Generator */
|
||||
UINT8 eg_type; /* percussive/non-percussive mode */
|
||||
UINT8 state; /* phase type */
|
||||
UINT32 TL; /* total level: TL << 2 */
|
||||
INT32 TLL; /* adjusted now TL */
|
||||
INT32 volume; /* envelope counter */
|
||||
UINT32 sl; /* sustain level: sl_tab[SL] */
|
||||
|
||||
UINT8 eg_sh_ar; /* (attack state) */
|
||||
UINT8 eg_sel_ar; /* (attack state) */
|
||||
UINT8 eg_sh_dr; /* (decay state) */
|
||||
UINT8 eg_sel_dr; /* (decay state) */
|
||||
UINT8 eg_sh_rr; /* (release state) */
|
||||
UINT8 eg_sel_rr; /* (release state) */
|
||||
|
||||
UINT32 key; /* 0 = KEY OFF, >0 = KEY ON */
|
||||
uint8_t eg_type; /* percussive/non-percussive mode */
|
||||
uint8_t state; /* phase type */
|
||||
uint32_t TL; /* total level: TL << 2 */
|
||||
int32_t TLL; /* adjusted now TL */
|
||||
int32_t volume; /* envelope counter */
|
||||
uint32_t sl; /* sustain level: sl_tab[SL] */
|
||||
uint8_t eg_sh_ar; /* (attack state) */
|
||||
uint8_t eg_sel_ar; /* (attack state) */
|
||||
uint8_t eg_sh_dr; /* (decay state) */
|
||||
uint8_t eg_sel_dr; /* (decay state) */
|
||||
uint8_t eg_sh_rr; /* (release state) */
|
||||
uint8_t eg_sel_rr; /* (release state) */
|
||||
uint32_t key; /* 0 = KEY OFF, >0 = KEY ON */
|
||||
|
||||
/* LFO */
|
||||
UINT32 AMmask; /* LFO Amplitude Modulation enable mask */
|
||||
UINT8 vib; /* LFO Phase Modulation enable flag (active high)*/
|
||||
uint32_t AMmask; /* LFO Amplitude Modulation enable mask */
|
||||
uint8_t vib; /* LFO Phase Modulation enable flag (active high)*/
|
||||
|
||||
/* waveform select */
|
||||
unsigned int wavetable;
|
||||
} OPL_SLOT;
|
||||
};
|
||||
|
||||
typedef struct{
|
||||
struct OPL_CH
|
||||
{
|
||||
OPL_SLOT SLOT[2];
|
||||
/* phase generator state */
|
||||
UINT32 block_fnum; /* block+fnum */
|
||||
UINT32 fc; /* Freq. Increment base */
|
||||
UINT32 ksl_base; /* KeyScaleLevel Base step */
|
||||
UINT8 kcode; /* key code (for key scaling) */
|
||||
uint32_t block_fnum; /* block+fnum */
|
||||
uint32_t fc; /* Freq. Increment base */
|
||||
uint32_t ksl_base; /* KeyScaleLevel Base step */
|
||||
uint8_t kcode; /* key code (for key scaling) */
|
||||
float LeftVol; /* volumes for stereo panning */
|
||||
float RightVol;
|
||||
} OPL_CH;
|
||||
};
|
||||
|
||||
/* OPL state */
|
||||
typedef struct fm_opl_f {
|
||||
struct FM_OPL
|
||||
{
|
||||
/* FM channel slots */
|
||||
OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels*/
|
||||
OPL_CH P_CH[9]; /* OPL/OPL2 chips have 9 channels*/
|
||||
|
||||
UINT32 eg_cnt; /* global envelope generator counter */
|
||||
UINT32 eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */
|
||||
UINT32 eg_timer_add; /* step of eg_timer */
|
||||
UINT32 eg_timer_overflow; /* envelope generator timer overflows every 1 sample (on real chip) */
|
||||
uint32_t eg_cnt; /* global envelope generator counter */
|
||||
uint32_t eg_timer; /* global envelope generator counter works at frequency = chipclock/72 */
|
||||
uint32_t eg_timer_add; /* step of eg_timer */
|
||||
uint32_t eg_timer_overflow; /* envelope generator timer overflows every 1 sample (on real chip) */
|
||||
|
||||
UINT8 rhythm; /* Rhythm mode */
|
||||
uint8_t rhythm; /* Rhythm mode */
|
||||
|
||||
UINT32 fn_tab[1024]; /* fnumber->increment counter */
|
||||
uint32_t fn_tab[1024]; /* fnumber->increment counter */
|
||||
|
||||
/* LFO */
|
||||
UINT8 lfo_am_depth;
|
||||
UINT8 lfo_pm_depth_range;
|
||||
UINT32 lfo_am_cnt;
|
||||
UINT32 lfo_am_inc;
|
||||
UINT32 lfo_pm_cnt;
|
||||
UINT32 lfo_pm_inc;
|
||||
|
||||
UINT32 noise_rng; /* 23 bit noise shift register */
|
||||
UINT32 noise_p; /* current noise 'phase' */
|
||||
UINT32 noise_f; /* current noise peroid */
|
||||
uint8_t lfo_am_depth;
|
||||
uint8_t lfo_pm_depth_range;
|
||||
uint32_t lfo_am_cnt;
|
||||
uint32_t lfo_am_inc;
|
||||
uint32_t lfo_pm_cnt;
|
||||
uint32_t lfo_pm_inc;
|
||||
|
||||
UINT8 wavesel; /* waveform select enable flag */
|
||||
uint32_t noise_rng; /* 23 bit noise shift register */
|
||||
uint32_t noise_p; /* current noise 'phase' */
|
||||
uint32_t noise_f; /* current noise period */
|
||||
|
||||
uint8_t wavesel; /* waveform select enable flag */
|
||||
|
||||
int T[2]; /* timer counters */
|
||||
UINT8 st[2]; /* timer enable */
|
||||
uint8_t st[2]; /* timer enable */
|
||||
|
||||
UINT8 address; /* address register */
|
||||
UINT8 status; /* status flag */
|
||||
UINT8 statusmask; /* status mask */
|
||||
UINT8 mode; /* Reg.08 : CSM,notesel,etc. */
|
||||
|
||||
uint8_t address; /* address register */
|
||||
uint8_t status; /* status flag */
|
||||
uint8_t statusmask; /* status mask */
|
||||
uint8_t mode; /* Reg.08 : CSM,notesel,etc. */
|
||||
|
||||
bool IsStereo; /* Write stereo output */
|
||||
} FM_OPL;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
@ -278,68 +271,67 @@ static const int slot_array[32]=
|
|||
/* table is 3dB/octave , DV converts this into 6dB/octave */
|
||||
/* 0.1875 is bit 0 weight of the envelope counter (volume) expressed in the 'decibel' scale */
|
||||
#define DV (0.1875/2.0)
|
||||
static const UINT32 ksl_tab[8*16]=
|
||||
static const uint32_t ksl_tab[8*16]=
|
||||
{
|
||||
/* OCT 0 */
|
||||
UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV),
|
||||
UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV),
|
||||
UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV),
|
||||
UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV),
|
||||
uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV),
|
||||
uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV),
|
||||
uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV),
|
||||
uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV),
|
||||
/* OCT 1 */
|
||||
UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV),
|
||||
UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV),
|
||||
UINT32(0.000/DV), UINT32(0.750/DV), UINT32(1.125/DV), UINT32(1.500/DV),
|
||||
UINT32(1.875/DV), UINT32(2.250/DV), UINT32(2.625/DV), UINT32(3.000/DV),
|
||||
uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV),
|
||||
uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV),
|
||||
uint32_t(0.000/DV), uint32_t(0.750/DV), uint32_t(1.125/DV), uint32_t(1.500/DV),
|
||||
uint32_t(1.875/DV), uint32_t(2.250/DV), uint32_t(2.625/DV), uint32_t(3.000/DV),
|
||||
/* OCT 2 */
|
||||
UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV),
|
||||
UINT32(0.000/DV), UINT32(1.125/DV), UINT32(1.875/DV), UINT32(2.625/DV),
|
||||
UINT32(3.000/DV), UINT32(3.750/DV), UINT32(4.125/DV), UINT32(4.500/DV),
|
||||
UINT32(4.875/DV), UINT32(5.250/DV), UINT32(5.625/DV), UINT32(6.000/DV),
|
||||
uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV),
|
||||
uint32_t(0.000/DV), uint32_t(1.125/DV), uint32_t(1.875/DV), uint32_t(2.625/DV),
|
||||
uint32_t(3.000/DV), uint32_t(3.750/DV), uint32_t(4.125/DV), uint32_t(4.500/DV),
|
||||
uint32_t(4.875/DV), uint32_t(5.250/DV), uint32_t(5.625/DV), uint32_t(6.000/DV),
|
||||
/* OCT 3 */
|
||||
UINT32(0.000/DV), UINT32(0.000/DV), UINT32(0.000/DV), UINT32(1.875/DV),
|
||||
UINT32(3.000/DV), UINT32(4.125/DV), UINT32(4.875/DV), UINT32(5.625/DV),
|
||||
UINT32(6.000/DV), UINT32(6.750/DV), UINT32(7.125/DV), UINT32(7.500/DV),
|
||||
UINT32(7.875/DV), UINT32(8.250/DV), UINT32(8.625/DV), UINT32(9.000/DV),
|
||||
uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(1.875/DV),
|
||||
uint32_t(3.000/DV), uint32_t(4.125/DV), uint32_t(4.875/DV), uint32_t(5.625/DV),
|
||||
uint32_t(6.000/DV), uint32_t(6.750/DV), uint32_t(7.125/DV), uint32_t(7.500/DV),
|
||||
uint32_t(7.875/DV), uint32_t(8.250/DV), uint32_t(8.625/DV), uint32_t(9.000/DV),
|
||||
/* OCT 4 */
|
||||
UINT32(0.000/DV), UINT32(0.000/DV), UINT32(3.000/DV), UINT32(4.875/DV),
|
||||
UINT32(6.000/DV), UINT32(7.125/DV), UINT32(7.875/DV), UINT32(8.625/DV),
|
||||
UINT32(9.000/DV), UINT32(9.750/DV),UINT32(10.125/DV),UINT32(10.500/DV),
|
||||
UINT32(10.875/DV),UINT32(11.250/DV),UINT32(11.625/DV),UINT32(12.000/DV),
|
||||
uint32_t(0.000/DV), uint32_t(0.000/DV), uint32_t(3.000/DV), uint32_t(4.875/DV),
|
||||
uint32_t(6.000/DV), uint32_t(7.125/DV), uint32_t(7.875/DV), uint32_t(8.625/DV),
|
||||
uint32_t(9.000/DV), uint32_t(9.750/DV),uint32_t(10.125/DV),uint32_t(10.500/DV),
|
||||
uint32_t(10.875/DV),uint32_t(11.250/DV),uint32_t(11.625/DV),uint32_t(12.000/DV),
|
||||
/* OCT 5 */
|
||||
UINT32(0.000/DV), UINT32(3.000/DV), UINT32(6.000/DV), UINT32(7.875/DV),
|
||||
UINT32(9.000/DV),UINT32(10.125/DV),UINT32(10.875/DV),UINT32(11.625/DV),
|
||||
UINT32(12.000/DV),UINT32(12.750/DV),UINT32(13.125/DV),UINT32(13.500/DV),
|
||||
UINT32(13.875/DV),UINT32(14.250/DV),UINT32(14.625/DV),UINT32(15.000/DV),
|
||||
uint32_t(0.000/DV), uint32_t(3.000/DV), uint32_t(6.000/DV), uint32_t(7.875/DV),
|
||||
uint32_t(9.000/DV),uint32_t(10.125/DV),uint32_t(10.875/DV),uint32_t(11.625/DV),
|
||||
uint32_t(12.000/DV),uint32_t(12.750/DV),uint32_t(13.125/DV),uint32_t(13.500/DV),
|
||||
uint32_t(13.875/DV),uint32_t(14.250/DV),uint32_t(14.625/DV),uint32_t(15.000/DV),
|
||||
/* OCT 6 */
|
||||
UINT32(0.000/DV), UINT32(6.000/DV), UINT32(9.000/DV),UINT32(10.875/DV),
|
||||
UINT32(12.000/DV),UINT32(13.125/DV),UINT32(13.875/DV),UINT32(14.625/DV),
|
||||
UINT32(15.000/DV),UINT32(15.750/DV),UINT32(16.125/DV),UINT32(16.500/DV),
|
||||
UINT32(16.875/DV),UINT32(17.250/DV),UINT32(17.625/DV),UINT32(18.000/DV),
|
||||
uint32_t(0.000/DV), uint32_t(6.000/DV), uint32_t(9.000/DV),uint32_t(10.875/DV),
|
||||
uint32_t(12.000/DV),uint32_t(13.125/DV),uint32_t(13.875/DV),uint32_t(14.625/DV),
|
||||
uint32_t(15.000/DV),uint32_t(15.750/DV),uint32_t(16.125/DV),uint32_t(16.500/DV),
|
||||
uint32_t(16.875/DV),uint32_t(17.250/DV),uint32_t(17.625/DV),uint32_t(18.000/DV),
|
||||
/* OCT 7 */
|
||||
UINT32(0.000/DV), UINT32(9.000/DV),UINT32(12.000/DV),UINT32(13.875/DV),
|
||||
UINT32(15.000/DV),UINT32(16.125/DV),UINT32(16.875/DV),UINT32(17.625/DV),
|
||||
UINT32(18.000/DV),UINT32(18.750/DV),UINT32(19.125/DV),UINT32(19.500/DV),
|
||||
UINT32(19.875/DV),UINT32(20.250/DV),UINT32(20.625/DV),UINT32(21.000/DV)
|
||||
uint32_t(0.000/DV), uint32_t(9.000/DV),uint32_t(12.000/DV),uint32_t(13.875/DV),
|
||||
uint32_t(15.000/DV),uint32_t(16.125/DV),uint32_t(16.875/DV),uint32_t(17.625/DV),
|
||||
uint32_t(18.000/DV),uint32_t(18.750/DV),uint32_t(19.125/DV),uint32_t(19.500/DV),
|
||||
uint32_t(19.875/DV),uint32_t(20.250/DV),uint32_t(20.625/DV),uint32_t(21.000/DV)
|
||||
};
|
||||
#undef DV
|
||||
|
||||
/* 0 / 3.0 / 1.5 / 6.0 dB/OCT */
|
||||
static const UINT32 ksl_shift[4] = { 31, 1, 2, 0 };
|
||||
static const uint32_t ksl_shift[4] = { 31, 1, 2, 0 };
|
||||
|
||||
|
||||
/* sustain level table (3dB per step) */
|
||||
/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
|
||||
#define SC(db) (UINT32) ( db * (2.0/ENV_STEP) )
|
||||
static const UINT32 sl_tab[16]={
|
||||
SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
|
||||
SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)
|
||||
#define SC(db) (uint32_t) ( db * (2.0/ENV_STEP) )
|
||||
static const uint32_t sl_tab[16]={
|
||||
SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7),
|
||||
SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31)
|
||||
};
|
||||
#undef SC
|
||||
|
||||
|
||||
#define RATE_STEPS (8)
|
||||
static const unsigned char eg_inc[15*RATE_STEPS]={
|
||||
|
||||
/*cycle:0 1 2 3 4 5 6 7*/
|
||||
|
||||
/* 0 */ 0,1, 0,1, 0,1, 0,1, /* rates 00..12 0 (increment by 0 or 1) */
|
||||
|
@ -366,7 +358,7 @@ static const unsigned char eg_inc[15*RATE_STEPS]={
|
|||
#define O(a) (a*RATE_STEPS)
|
||||
|
||||
/*note that there is no O(13) in this table - it's directly in the code */
|
||||
static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */
|
||||
static const unsigned char eg_rate_select[16+64+16]={ /* Envelope Generator rates (16 + 64 rates + 16 RKS) */
|
||||
/* 16 infinite time rates */
|
||||
O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14),
|
||||
O(14),O(14),O(14),O(14),O(14),O(14),O(14),O(14),
|
||||
|
@ -407,7 +399,7 @@ O(12),O(12),O(12),O(12),O(12),O(12),O(12),O(12),
|
|||
/*mask 4095, 2047, 1023, 511, 255, 127, 63, 31, 15, 7, 3, 1, 0, 0, 0, 0 */
|
||||
|
||||
#define O(a) (a*1)
|
||||
static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */
|
||||
static const unsigned char eg_rate_shift[16+64+16]={ /* Envelope Generator counter shifts (16 + 64 rates + 16 RKS) */
|
||||
/* 16 infinite time rates */
|
||||
O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
|
||||
O(0),O(0),O(0),O(0),O(0),O(0),O(0),O(0),
|
||||
|
@ -446,22 +438,22 @@ O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),O( 0),
|
|||
|
||||
/* multiple table */
|
||||
#define ML 2
|
||||
static const UINT8 mul_tab[16]= {
|
||||
static const uint8_t mul_tab[16]= {
|
||||
/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,10,12,12,15,15 */
|
||||
UINT8(0.50*ML), UINT8(1.00*ML), UINT8(2.00*ML), UINT8(3.00*ML), UINT8(4.00*ML), UINT8(5.00*ML), UINT8(6.00*ML), UINT8(7.00*ML),
|
||||
UINT8(8.00*ML), UINT8(9.00*ML),UINT8(10.00*ML),UINT8(10.00*ML),UINT8(12.00*ML),UINT8(12.00*ML),UINT8(15.00*ML),UINT8(15.00*ML)
|
||||
uint8_t(0.50*ML), uint8_t(1.00*ML), uint8_t(2.00*ML), uint8_t(3.00*ML), uint8_t(4.00*ML), uint8_t(5.00*ML), uint8_t(6.00*ML), uint8_t(7.00*ML),
|
||||
uint8_t(8.00*ML), uint8_t(9.00*ML),uint8_t(10.00*ML),uint8_t(10.00*ML),uint8_t(12.00*ML),uint8_t(12.00*ML),uint8_t(15.00*ML),uint8_t(15.00*ML)
|
||||
};
|
||||
#undef ML
|
||||
|
||||
/* TL_TAB_LEN is calculated as:
|
||||
* 12 - sinus amplitude bits (Y axis)
|
||||
* 2 - sinus sign bit (Y axis)
|
||||
* TL_RES_LEN - sinus resolution (X axis)
|
||||
/* TL_TAB_LEN is calculated as:
|
||||
* 12 - sinus amplitude bits (Y axis)
|
||||
* 2 - sinus sign bit (Y axis)
|
||||
* TL_RES_LEN - sinus resolution (X axis)
|
||||
*/
|
||||
#define TL_TAB_LEN (12*2*TL_RES_LEN)
|
||||
static signed int tl_tab[TL_TAB_LEN];
|
||||
|
||||
#define ENV_QUIET (TL_TAB_LEN>>4)
|
||||
#define ENV_QUIET (TL_TAB_LEN>>4)
|
||||
|
||||
/* sin waveform table in 'decibel' scale */
|
||||
/* four waveforms on OPL2 type chips */
|
||||
|
@ -473,17 +465,17 @@ static unsigned int sin_tab[SIN_LEN * 4];
|
|||
|
||||
Length: 210 elements.
|
||||
|
||||
Each of the elements has to be repeated
|
||||
exactly 64 times (on 64 consecutive samples).
|
||||
The whole table takes: 64 * 210 = 13440 samples.
|
||||
Each of the elements has to be repeated
|
||||
exactly 64 times (on 64 consecutive samples).
|
||||
The whole table takes: 64 * 210 = 13440 samples.
|
||||
|
||||
When AM = 1 data is used directly
|
||||
When AM = 0 data is divided by 4 before being used (loosing precision is important)
|
||||
When AM = 1 data is used directly
|
||||
When AM = 0 data is divided by 4 before being used (losing precision is important)
|
||||
*/
|
||||
|
||||
#define LFO_AM_TAB_ELEMENTS 210
|
||||
|
||||
static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = {
|
||||
static const uint8_t lfo_am_table[LFO_AM_TAB_ELEMENTS] = {
|
||||
0,0,0,0,0,0,0,
|
||||
1,1,1,1,
|
||||
2,2,2,2,
|
||||
|
@ -539,39 +531,38 @@ static const UINT8 lfo_am_table[LFO_AM_TAB_ELEMENTS] = {
|
|||
};
|
||||
|
||||
/* LFO Phase Modulation table (verified on real YM3812) */
|
||||
static const INT8 lfo_pm_table[8*8*2] = {
|
||||
|
||||
static const int8_t lfo_pm_table[8*8*2] = {
|
||||
/* FNUM2/FNUM = 00 0xxxxxxx (0x0000) */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 1*/
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 1*/
|
||||
|
||||
/* FNUM2/FNUM = 00 1xxxxxxx (0x0080) */
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/
|
||||
1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 1*/
|
||||
0, 0, 0, 0, 0, 0, 0, 0, /*LFO PM depth = 0*/
|
||||
1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 1*/
|
||||
|
||||
/* FNUM2/FNUM = 01 0xxxxxxx (0x0100) */
|
||||
1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/
|
||||
2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 1*/
|
||||
1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/
|
||||
2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 1*/
|
||||
|
||||
/* FNUM2/FNUM = 01 1xxxxxxx (0x0180) */
|
||||
1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/
|
||||
3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 1*/
|
||||
1, 0, 0, 0,-1, 0, 0, 0, /*LFO PM depth = 0*/
|
||||
3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 1*/
|
||||
|
||||
/* FNUM2/FNUM = 10 0xxxxxxx (0x0200) */
|
||||
2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/
|
||||
4, 2, 0,-2,-4,-2, 0, 2, /*LFO PM depth = 1*/
|
||||
2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/
|
||||
4, 2, 0,-2,-4,-2, 0, 2, /*LFO PM depth = 1*/
|
||||
|
||||
/* FNUM2/FNUM = 10 1xxxxxxx (0x0280) */
|
||||
2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/
|
||||
5, 2, 0,-2,-5,-2, 0, 2, /*LFO PM depth = 1*/
|
||||
2, 1, 0,-1,-2,-1, 0, 1, /*LFO PM depth = 0*/
|
||||
5, 2, 0,-2,-5,-2, 0, 2, /*LFO PM depth = 1*/
|
||||
|
||||
/* FNUM2/FNUM = 11 0xxxxxxx (0x0300) */
|
||||
3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/
|
||||
6, 3, 0,-3,-6,-3, 0, 3, /*LFO PM depth = 1*/
|
||||
3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/
|
||||
6, 3, 0,-3,-6,-3, 0, 3, /*LFO PM depth = 1*/
|
||||
|
||||
/* FNUM2/FNUM = 11 1xxxxxxx (0x0380) */
|
||||
3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/
|
||||
7, 3, 0,-3,-7,-3, 0, 3 /*LFO PM depth = 1*/
|
||||
3, 1, 0,-1,-3,-1, 0, 1, /*LFO PM depth = 0*/
|
||||
7, 3, 0,-3,-7,-3, 0, 3 /*LFO PM depth = 1*/
|
||||
};
|
||||
|
||||
|
||||
|
@ -582,8 +573,8 @@ static int num_lock = 0;
|
|||
static signed int phase_modulation; /* phase modulation input (SLOT 2) */
|
||||
static signed int output;
|
||||
|
||||
static UINT32 LFO_AM;
|
||||
static INT32 LFO_PM;
|
||||
static uint32_t LFO_AM;
|
||||
static int32_t LFO_PM;
|
||||
|
||||
static bool CalcVoice (FM_OPL *OPL, int voice, float *buffer, int length);
|
||||
static bool CalcRhythm (FM_OPL *OPL, float *buffer, int length);
|
||||
|
@ -591,21 +582,21 @@ static bool CalcRhythm (FM_OPL *OPL, float *buffer, int length);
|
|||
|
||||
|
||||
/* status set and IRQ handling */
|
||||
INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag)
|
||||
static inline void OPL_STATUS_SET(FM_OPL *OPL,int flag)
|
||||
{
|
||||
/* set status flag */
|
||||
OPL->status |= flag;
|
||||
if(!(OPL->status & 0x80))
|
||||
{
|
||||
if(OPL->status & OPL->statusmask)
|
||||
{ /* IRQ on */
|
||||
{ /* IRQ on */
|
||||
OPL->status |= 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* status reset and IRQ handling */
|
||||
INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag)
|
||||
static inline void OPL_STATUS_RESET(FM_OPL *OPL,int flag)
|
||||
{
|
||||
/* reset status flag */
|
||||
OPL->status &=~flag;
|
||||
|
@ -619,7 +610,7 @@ INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag)
|
|||
}
|
||||
|
||||
/* IRQ mask set */
|
||||
INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag)
|
||||
static inline void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag)
|
||||
{
|
||||
OPL->statusmask = flag;
|
||||
/* IRQ handling check */
|
||||
|
@ -629,13 +620,13 @@ INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag)
|
|||
|
||||
|
||||
/* advance LFO to next sample */
|
||||
INLINE void advance_lfo(FM_OPL *OPL)
|
||||
static inline void advance_lfo(FM_OPL *OPL)
|
||||
{
|
||||
UINT8 tmp;
|
||||
uint8_t tmp;
|
||||
|
||||
/* LFO */
|
||||
OPL->lfo_am_cnt += OPL->lfo_am_inc;
|
||||
if (OPL->lfo_am_cnt >= (UINT32)(LFO_AM_TAB_ELEMENTS<<LFO_SH) ) /* lfo_am_table is 210 elements long */
|
||||
if (OPL->lfo_am_cnt >= (uint32_t)(LFO_AM_TAB_ELEMENTS<<LFO_SH) ) /* lfo_am_table is 210 elements long */
|
||||
OPL->lfo_am_cnt -= (LFO_AM_TAB_ELEMENTS<<LFO_SH);
|
||||
|
||||
tmp = lfo_am_table[ OPL->lfo_am_cnt >> LFO_SH ];
|
||||
|
@ -650,7 +641,7 @@ INLINE void advance_lfo(FM_OPL *OPL)
|
|||
}
|
||||
|
||||
/* advance to next sample */
|
||||
INLINE void advance(FM_OPL *OPL, int loch, int hich)
|
||||
static inline void advance(FM_OPL *OPL, int loch, int hich)
|
||||
{
|
||||
OPL_CH *CH;
|
||||
OPL_SLOT *op;
|
||||
|
@ -690,28 +681,28 @@ INLINE void advance(FM_OPL *OPL, int loch, int hich)
|
|||
}
|
||||
break;
|
||||
|
||||
case EG_DEC: /* decay phase */
|
||||
case EG_DEC: /* decay phase */
|
||||
if ( !(OPL->eg_cnt & ((1<<op->eg_sh_dr)-1) ) )
|
||||
{
|
||||
op->volume += eg_inc[op->eg_sel_dr + ((OPL->eg_cnt>>op->eg_sh_dr)&7)];
|
||||
|
||||
if ( op->volume >= (INT32)op->sl )
|
||||
if ( op->volume >= (int32_t)op->sl )
|
||||
op->state = EG_SUS;
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case EG_SUS: /* sustain phase */
|
||||
case EG_SUS: /* sustain phase */
|
||||
|
||||
/* this is important behaviour:
|
||||
one can change percusive/non-percussive modes on the fly and
|
||||
the chip will remain in sustain phase - verified on real YM3812 */
|
||||
|
||||
if(op->eg_type) /* non-percussive mode */
|
||||
if(op->eg_type) /* non-percussive mode */
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
else /* percussive mode */
|
||||
else /* percussive mode */
|
||||
{
|
||||
/* during sustain phase chip adds Release Rate (in percussive mode) */
|
||||
if ( !(OPL->eg_cnt & ((1<<op->eg_sh_rr)-1) ) )
|
||||
|
@ -725,7 +716,7 @@ INLINE void advance(FM_OPL *OPL, int loch, int hich)
|
|||
}
|
||||
break;
|
||||
|
||||
case EG_REL: /* release phase */
|
||||
case EG_REL: /* release phase */
|
||||
if ( !(OPL->eg_cnt & ((1<<op->eg_sh_rr)-1) ) )
|
||||
{
|
||||
op->volume += eg_inc[op->eg_sel_rr + ((OPL->eg_cnt>>op->eg_sh_rr)&7)];
|
||||
|
@ -746,7 +737,7 @@ INLINE void advance(FM_OPL *OPL, int loch, int hich)
|
|||
/* Phase Generator */
|
||||
if(op->vib)
|
||||
{
|
||||
UINT8 block;
|
||||
uint8_t block;
|
||||
unsigned int block_fnum = CH->block_fnum;
|
||||
|
||||
unsigned int fnum_lfo = (block_fnum&0x0380) >> 7;
|
||||
|
@ -772,37 +763,37 @@ INLINE void advance(FM_OPL *OPL, int loch, int hich)
|
|||
}
|
||||
}
|
||||
|
||||
INLINE void advance_noise(FM_OPL *OPL)
|
||||
static inline void advance_noise(FM_OPL *OPL)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* The Noise Generator of the YM3812 is 23-bit shift register.
|
||||
* Period is equal to 2^23-2 samples.
|
||||
* Register works at sampling frequency of the chip, so output
|
||||
* can change on every sample.
|
||||
/* The Noise Generator of the YM3812 is 23-bit shift register.
|
||||
* Period is equal to 2^23-2 samples.
|
||||
* Register works at sampling frequency of the chip, so output
|
||||
* can change on every sample.
|
||||
*
|
||||
* Output of the register and input to the bit 22 is:
|
||||
* bit0 XOR bit14 XOR bit15 XOR bit22
|
||||
* Output of the register and input to the bit 22 is:
|
||||
* bit0 XOR bit14 XOR bit15 XOR bit22
|
||||
*
|
||||
* Simply use bit 22 as the noise output.
|
||||
* Simply use bit 22 as the noise output.
|
||||
*/
|
||||
|
||||
OPL->noise_p += OPL->noise_f;
|
||||
i = OPL->noise_p >> FREQ_SH; /* number of events (shifts of the shift register) */
|
||||
i = OPL->noise_p >> FREQ_SH; /* number of events (shifts of the shift register) */
|
||||
OPL->noise_p &= FREQ_MASK;
|
||||
while (i)
|
||||
{
|
||||
/*
|
||||
UINT32 j;
|
||||
uint32_t j;
|
||||
j = ( (OPL->noise_rng) ^ (OPL->noise_rng>>14) ^ (OPL->noise_rng>>15) ^ (OPL->noise_rng>>22) ) & 1;
|
||||
OPL->noise_rng = (j<<22) | (OPL->noise_rng>>1);
|
||||
*/
|
||||
|
||||
/*
|
||||
Instead of doing all the logic operations above, we
|
||||
use a trick here (and use bit 0 as the noise output).
|
||||
The difference is only that the noise bit changes one
|
||||
step ahead. This doesn't matter since we don't know
|
||||
Instead of doing all the logic operations above, we
|
||||
use a trick here (and use bit 0 as the noise output).
|
||||
The difference is only that the noise bit changes one
|
||||
step ahead. This doesn't matter since we don't know
|
||||
what is real state of the noise_rng after the reset.
|
||||
*/
|
||||
|
||||
|
@ -814,9 +805,9 @@ INLINE void advance_noise(FM_OPL *OPL)
|
|||
}
|
||||
|
||||
|
||||
INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab)
|
||||
static inline signed int op_calc(uint32_t phase, unsigned int env, signed int pm, unsigned int wave_tab)
|
||||
{
|
||||
UINT32 p;
|
||||
uint32_t p;
|
||||
|
||||
p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + (pm<<16))) >> FREQ_SH ) & SIN_MASK) ];
|
||||
|
||||
|
@ -825,9 +816,9 @@ INLINE signed int op_calc(UINT32 phase, unsigned int env, signed int pm, unsigne
|
|||
return tl_tab[p];
|
||||
}
|
||||
|
||||
INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsigned int wave_tab)
|
||||
static inline signed int op_calc1(uint32_t phase, unsigned int env, signed int pm, unsigned int wave_tab)
|
||||
{
|
||||
UINT32 p;
|
||||
uint32_t p;
|
||||
|
||||
p = (env<<4) + sin_tab[wave_tab + ((((signed int)((phase & ~FREQ_MASK) + pm )) >> FREQ_SH ) & SIN_MASK) ];
|
||||
|
||||
|
@ -837,10 +828,10 @@ INLINE signed int op_calc1(UINT32 phase, unsigned int env, signed int pm, unsign
|
|||
}
|
||||
|
||||
|
||||
#define volume_calc(OP) ((OP)->TLL + ((UINT32)(OP)->volume) + (LFO_AM & (OP)->AMmask))
|
||||
#define volume_calc(OP) ((OP)->TLL + ((uint32_t)(OP)->volume) + (LFO_AM & (OP)->AMmask))
|
||||
|
||||
/* calculate output */
|
||||
INLINE float OPL_CALC_CH( OPL_CH *CH )
|
||||
static inline float OPL_CALC_CH( OPL_CH *CH )
|
||||
{
|
||||
OPL_SLOT *SLOT;
|
||||
unsigned int env;
|
||||
|
@ -875,9 +866,9 @@ INLINE float OPL_CALC_CH( OPL_CH *CH )
|
|||
}
|
||||
|
||||
/*
|
||||
operators used in the rhythm sounds generation process:
|
||||
operators used in the rhythm sounds generation process:
|
||||
|
||||
Envelope Generator:
|
||||
Envelope Generator:
|
||||
|
||||
channel operator register number Bass High Snare Tom Top
|
||||
/ slot number TL ARDR SLRR Wave Drum Hat Drum Tom Cymbal
|
||||
|
@ -911,7 +902,7 @@ number number BLK/FNUM2 FNUM Drum Hat Drum Tom Cymbal
|
|||
|
||||
/* calculate rhythm */
|
||||
|
||||
INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise )
|
||||
static inline void OPL_CALC_RH( OPL_CH *CH, unsigned int noise )
|
||||
{
|
||||
OPL_SLOT *SLOT;
|
||||
signed int out;
|
||||
|
@ -988,7 +979,7 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise )
|
|||
|
||||
/* when res1 = 0 phase = 0x000 | 0xd0; */
|
||||
/* when res1 = 1 phase = 0x200 | (0xd0>>2); */
|
||||
UINT32 phase = res1 ? (0x200|(0xd0>>2)) : 0xd0;
|
||||
uint32_t phase = res1 ? (0x200|(0xd0>>2)) : 0xd0;
|
||||
|
||||
/* enable gate based on frequency of operator 2 in channel 8 */
|
||||
unsigned char bit5e= ((CH[8].SLOT[SLOT2].Cnt>>FREQ_SH)>>5)&1;
|
||||
|
@ -1029,7 +1020,7 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise )
|
|||
|
||||
/* when bit8 = 0 phase = 0x100; */
|
||||
/* when bit8 = 1 phase = 0x200; */
|
||||
UINT32 phase = bit8 ? 0x200 : 0x100;
|
||||
uint32_t phase = bit8 ? 0x200 : 0x100;
|
||||
|
||||
/* Noise bit XOR'es phase by 0x100 */
|
||||
/* when noisebit = 0 pass the phase from calculation above */
|
||||
|
@ -1059,7 +1050,7 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise )
|
|||
|
||||
/* when res1 = 0 phase = 0x000 | 0x100; */
|
||||
/* when res1 = 1 phase = 0x200 | 0x100; */
|
||||
UINT32 phase = res1 ? 0x300 : 0x100;
|
||||
uint32_t phase = res1 ? 0x300 : 0x100;
|
||||
|
||||
/* enable gate based on frequency of operator 2 in channel 8 */
|
||||
unsigned char bit5e= ((CH[8].SLOT[SLOT2].Cnt>>FREQ_SH)>>5)&1;
|
||||
|
@ -1073,7 +1064,6 @@ INLINE void OPL_CALC_RH( OPL_CH *CH, unsigned int noise )
|
|||
|
||||
output += op_calc(phase<<FREQ_SH, env, 0, CH[8].SLOT[SLOT2].wavetable) * 2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1100,11 +1090,11 @@ static void init_tables(void)
|
|||
/* we never reach (1<<16) here due to the (x+1) */
|
||||
/* result fits within 16 bits at maximum */
|
||||
|
||||
n = (int)m; /* 16 bits here */
|
||||
n >>= 4; /* 12 bits here */
|
||||
n = (int)m; /* 16 bits here */
|
||||
n >>= 4; /* 12 bits here */
|
||||
n = (n+1)>>1; /* round to nearest */
|
||||
/* 11 bits here (rounded) */
|
||||
n <<= 1; /* 12 bits here (as in real chip) */
|
||||
n <<= 1; /* 12 bits here (as in real chip) */
|
||||
tl_tab[ x*2 + 0 ] = n;
|
||||
tl_tab[ x*2 + 1 ] = -tl_tab[ x*2 + 0 ];
|
||||
|
||||
|
@ -1123,14 +1113,14 @@ static void init_tables(void)
|
|||
/* we never reach zero here due to ((i*2)+1) */
|
||||
|
||||
if (m>0.0)
|
||||
o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */
|
||||
o = 8*log(1.0/m)/log(2.0); /* convert to 'decibels' */
|
||||
else
|
||||
o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */
|
||||
o = 8*log(-1.0/m)/log(2.0); /* convert to 'decibels' */
|
||||
|
||||
o = o / (ENV_STEP/4);
|
||||
|
||||
n = (int)(2.0*o);
|
||||
if (n&1) /* round to nearest */
|
||||
if (n&1) /* round to nearest */
|
||||
n = (n>>1)+1;
|
||||
else
|
||||
n = n>>1;
|
||||
|
@ -1176,18 +1166,18 @@ static void OPL_initalize(FM_OPL *OPL)
|
|||
for( i=0 ; i < 1024 ; i++ )
|
||||
{
|
||||
/* opn phase increment counter = 20bit */
|
||||
OPL->fn_tab[i] = (UINT32)( (double)i * 64 * OPL_FREQBASE * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */
|
||||
OPL->fn_tab[i] = (uint32_t)( (double)i * 64 * OPL_FREQBASE * (1<<(FREQ_SH-10)) ); /* -10 because chip works with 10.10 fixed point, while we use 16.16 */
|
||||
}
|
||||
|
||||
/* Amplitude modulation: 27 output levels (triangle waveform); 1 level takes one of: 192, 256 or 448 samples */
|
||||
/* One entry from LFO_AM_TABLE lasts for 64 samples */
|
||||
OPL->lfo_am_inc = UINT32((1.0 / 64.0 ) * (1<<LFO_SH) * OPL_FREQBASE);
|
||||
OPL->lfo_am_inc = uint32_t((1.0 / 64.0 ) * (1<<LFO_SH) * OPL_FREQBASE);
|
||||
|
||||
/* Vibrato: 8 output levels (triangle waveform); 1 level takes 1024 samples */
|
||||
OPL->lfo_pm_inc = UINT32((1.0 / 1024.0) * (1<<LFO_SH) * OPL_FREQBASE);
|
||||
OPL->lfo_pm_inc = uint32_t((1.0 / 1024.0) * (1<<LFO_SH) * OPL_FREQBASE);
|
||||
|
||||
OPL->eg_timer_add = UINT32((1<<EG_SH) * OPL_FREQBASE);
|
||||
OPL->eg_timer_overflow = UINT32(( 1 ) * (1<<EG_SH));
|
||||
OPL->eg_timer_add = uint32_t((1<<EG_SH) * OPL_FREQBASE);
|
||||
OPL->eg_timer_overflow = uint32_t(( 1 ) * (1<<EG_SH));
|
||||
|
||||
// [RH] Support full MIDI panning. (But default to mono and center panning.)
|
||||
OPL->IsStereo = false;
|
||||
|
@ -1198,7 +1188,7 @@ static void OPL_initalize(FM_OPL *OPL)
|
|||
}
|
||||
}
|
||||
|
||||
INLINE void FM_KEYON(OPL_SLOT *SLOT, UINT32 key_set)
|
||||
static inline void FM_KEYON(OPL_SLOT *SLOT, uint32_t key_set)
|
||||
{
|
||||
if( !SLOT->key )
|
||||
{
|
||||
|
@ -1210,7 +1200,7 @@ INLINE void FM_KEYON(OPL_SLOT *SLOT, UINT32 key_set)
|
|||
SLOT->key |= key_set;
|
||||
}
|
||||
|
||||
INLINE void FM_KEYOFF(OPL_SLOT *SLOT, UINT32 key_clr)
|
||||
static inline void FM_KEYOFF(OPL_SLOT *SLOT, uint32_t key_clr)
|
||||
{
|
||||
if( SLOT->key )
|
||||
{
|
||||
|
@ -1226,7 +1216,7 @@ INLINE void FM_KEYOFF(OPL_SLOT *SLOT, UINT32 key_clr)
|
|||
}
|
||||
|
||||
/* update phase increment counter of operator (also update the EG rates if necessary) */
|
||||
void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT)
|
||||
static inline void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT)
|
||||
{
|
||||
int ksr;
|
||||
|
||||
|
@ -1257,7 +1247,7 @@ void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT)
|
|||
}
|
||||
|
||||
/* set multi,am,vib,EG-TYP,KSR,mul */
|
||||
void set_mul(FM_OPL *OPL,int slot,int v)
|
||||
static inline void set_mul(FM_OPL *OPL,int slot,int v)
|
||||
{
|
||||
OPL_CH *CH = &OPL->P_CH[slot/2];
|
||||
OPL_SLOT *SLOT = &CH->SLOT[slot&1];
|
||||
|
@ -1271,7 +1261,7 @@ void set_mul(FM_OPL *OPL,int slot,int v)
|
|||
}
|
||||
|
||||
/* set ksl & tl */
|
||||
void set_ksl_tl(FM_OPL *OPL,int slot,int v)
|
||||
static inline void set_ksl_tl(FM_OPL *OPL,int slot,int v)
|
||||
{
|
||||
OPL_CH *CH = &OPL->P_CH[slot/2];
|
||||
OPL_SLOT *SLOT = &CH->SLOT[slot&1];
|
||||
|
@ -1283,7 +1273,7 @@ void set_ksl_tl(FM_OPL *OPL,int slot,int v)
|
|||
}
|
||||
|
||||
/* set attack rate & decay rate */
|
||||
INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v)
|
||||
static inline void set_ar_dr(FM_OPL *OPL,int slot,int v)
|
||||
{
|
||||
OPL_CH *CH = &OPL->P_CH[slot/2];
|
||||
OPL_SLOT *SLOT = &CH->SLOT[slot&1];
|
||||
|
@ -1307,7 +1297,7 @@ INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v)
|
|||
}
|
||||
|
||||
/* set sustain level & release rate */
|
||||
void set_sl_rr(FM_OPL *OPL,int slot,int v)
|
||||
static inline void set_sl_rr(FM_OPL *OPL,int slot,int v)
|
||||
{
|
||||
OPL_CH *CH = &OPL->P_CH[slot/2];
|
||||
OPL_SLOT *SLOT = &CH->SLOT[slot&1];
|
||||
|
@ -1333,31 +1323,32 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
|
|||
|
||||
switch(r&0xe0)
|
||||
{
|
||||
case 0x00: /* 00-1f:control */
|
||||
case 0x00: /* 00-1f:control */
|
||||
switch(r&0x1f)
|
||||
{
|
||||
case 0x01: /* waveform select enable */
|
||||
OPL->wavesel = v&0x20;
|
||||
break;
|
||||
case 0x02: /* Timer 1 */
|
||||
case 0x02: /* Timer 1 */
|
||||
OPL->T[0] = (256-v)*4;
|
||||
break;
|
||||
case 0x03: /* Timer 2 */
|
||||
case 0x03: /* Timer 2 */
|
||||
OPL->T[1] = (256-v)*16;
|
||||
break;
|
||||
case 0x04: /* IRQ clear / mask and Timer enable */
|
||||
case 0x04: /* IRQ clear / mask and Timer enable */
|
||||
if(v&0x80)
|
||||
{ /* IRQ flag clear */
|
||||
{ /* IRQ flag clear */
|
||||
OPL_STATUS_RESET(OPL,0x7f-0x08); /* don't reset BFRDY flag or we will have to call deltat module to set the flag */
|
||||
}
|
||||
else
|
||||
{ /* set IRQ mask ,timer enable*/
|
||||
UINT8 st1 = v&1;
|
||||
UINT8 st2 = (v>>1)&1;
|
||||
{ /* set IRQ mask ,timer enable*/
|
||||
uint8_t st1 = v&1;
|
||||
uint8_t st2 = (v>>1)&1;
|
||||
|
||||
/* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */
|
||||
OPL_STATUS_RESET(OPL, v & (0x78-0x08) );
|
||||
OPL_STATUSMASK_SET(OPL, (~v) & 0x78 );
|
||||
|
||||
/* timer 2 */
|
||||
if(OPL->st[1] != st2)
|
||||
{
|
||||
|
@ -1375,7 +1366,7 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
|
|||
break;
|
||||
}
|
||||
break;
|
||||
case 0x20: /* am ON, vib ON, ksr, eg_type, mul */
|
||||
case 0x20: /* am ON, vib ON, ksr, eg_type, mul */
|
||||
slot = slot_array[r&0x1f];
|
||||
if(slot < 0) return;
|
||||
set_mul(OPL,slot,v);
|
||||
|
@ -1396,7 +1387,7 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
|
|||
set_sl_rr(OPL,slot,v);
|
||||
break;
|
||||
case 0xa0:
|
||||
if (r == 0xbd) /* am depth, vibrato depth, r,bd,sd,tom,tc,hh */
|
||||
if (r == 0xbd) /* am depth, vibrato depth, r,bd,sd,tom,tc,hh */
|
||||
{
|
||||
OPL->lfo_am_depth = v & 0x80;
|
||||
OPL->lfo_pm_depth_range = (v&0x40) ? 8 : 0;
|
||||
|
@ -1449,11 +1440,11 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
|
|||
if( (r&0x0f) > 8) return;
|
||||
CH = &OPL->P_CH[r&0x0f];
|
||||
if(!(r&0x10))
|
||||
{ /* a0-a8 */
|
||||
{ /* a0-a8 */
|
||||
block_fnum = (CH->block_fnum&0x1f00) | v;
|
||||
}
|
||||
else
|
||||
{ /* b0-b8 */
|
||||
{ /* b0-b8 */
|
||||
block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff);
|
||||
|
||||
if(v&0x20)
|
||||
|
@ -1468,9 +1459,9 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
|
|||
}
|
||||
}
|
||||
/* update */
|
||||
if(CH->block_fnum != (UINT32)block_fnum)
|
||||
if(CH->block_fnum != (uint32_t)block_fnum)
|
||||
{
|
||||
UINT8 block = block_fnum >> 10;
|
||||
uint8_t block = block_fnum >> 10;
|
||||
|
||||
CH->block_fnum = block_fnum;
|
||||
|
||||
|
@ -1480,13 +1471,13 @@ static void OPLWriteReg(FM_OPL *OPL, int r, int v)
|
|||
/* BLK 2,1,0 bits -> bits 3,2,1 of kcode */
|
||||
CH->kcode = (CH->block_fnum&0x1c00)>>9;
|
||||
|
||||
/* the info below is actually opposite to what is stated in the Manuals (verifed on real YM3812) */
|
||||
/* the info below is actually opposite to what is stated in the Manuals (verifed on real YM3812) */
|
||||
/* if notesel == 0 -> lsb of kcode is bit 10 (MSB) of fnum */
|
||||
/* if notesel == 1 -> lsb of kcode is bit 9 (MSB-1) of fnum */
|
||||
if (OPL->mode&0x40)
|
||||
CH->kcode |= (CH->block_fnum&0x100)>>8; /* notesel == 1 */
|
||||
CH->kcode |= (CH->block_fnum&0x100)>>8; /* notesel == 1 */
|
||||
else
|
||||
CH->kcode |= (CH->block_fnum&0x200)>>9; /* notesel == 0 */
|
||||
CH->kcode |= (CH->block_fnum&0x200)>>9; /* notesel == 0 */
|
||||
|
||||
/* refresh Total Level in both SLOTs of this channel */
|
||||
CH->SLOT[SLOT1].TLL = CH->SLOT[SLOT1].TL + (CH->ksl_base>>CH->SLOT[SLOT1].ksl);
|
||||
|
@ -1527,8 +1518,8 @@ static void OPLResetChip(FM_OPL *OPL)
|
|||
OPL->eg_timer = 0;
|
||||
OPL->eg_cnt = 0;
|
||||
|
||||
OPL->noise_rng = 1; /* noise shift register */
|
||||
OPL->mode = 0; /* normal mode */
|
||||
OPL->noise_rng = 1; /* noise shift register */
|
||||
OPL->mode = 0; /* normal mode */
|
||||
OPL_STATUS_RESET(OPL,0x7f);
|
||||
|
||||
/* reset with register write */
|
||||
|
@ -1604,15 +1595,15 @@ public:
|
|||
{
|
||||
int i;
|
||||
|
||||
UINT8 rhythm = Chip.rhythm&0x20;
|
||||
uint8_t rhythm = Chip.rhythm&0x20;
|
||||
|
||||
UINT32 lfo_am_cnt_bak = Chip.lfo_am_cnt;
|
||||
UINT32 eg_timer_bak = Chip.eg_timer;
|
||||
UINT32 eg_cnt_bak = Chip.eg_cnt;
|
||||
uint32_t lfo_am_cnt_bak = Chip.lfo_am_cnt;
|
||||
uint32_t eg_timer_bak = Chip.eg_timer;
|
||||
uint32_t eg_cnt_bak = Chip.eg_cnt;
|
||||
|
||||
UINT32 lfo_am_cnt_out = lfo_am_cnt_bak;
|
||||
UINT32 eg_timer_out = eg_timer_bak;
|
||||
UINT32 eg_cnt_out = eg_cnt_bak;
|
||||
uint32_t lfo_am_cnt_out = lfo_am_cnt_bak;
|
||||
uint32_t eg_timer_out = eg_timer_bak;
|
||||
uint32_t eg_cnt_out = eg_cnt_bak;
|
||||
|
||||
for (i = 0; i <= (rhythm ? 5 : 8); ++i)
|
||||
{
|
||||
|
|
|
@ -69,12 +69,12 @@ musicBlock::~musicBlock ()
|
|||
if (OPLinstruments != NULL) free(OPLinstruments);
|
||||
}
|
||||
|
||||
void musicBlock::writeFrequency(uint slot, uint note, int pitch, uint keyOn)
|
||||
void musicBlock::writeFrequency(uint32_t slot, uint32_t note, int pitch, uint32_t keyOn)
|
||||
{
|
||||
io->OPLwriteFreq (slot, note, pitch, keyOn);
|
||||
}
|
||||
|
||||
void musicBlock::writeModulation(uint slot, struct OPL2instrument *instr, int state)
|
||||
void musicBlock::writeModulation(uint32_t slot, struct OPL2instrument *instr, int state)
|
||||
{
|
||||
if (state)
|
||||
state = 0x40; /* enable Frequency Vibrato */
|
||||
|
@ -83,17 +83,17 @@ void musicBlock::writeModulation(uint slot, struct OPL2instrument *instr, int st
|
|||
instr->trem_vibr_2 | state);
|
||||
}
|
||||
|
||||
uint musicBlock::calcVolume(uint channelVolume, uint channelExpression, uint noteVolume)
|
||||
uint32_t musicBlock::calcVolume(uint32_t channelVolume, uint32_t channelExpression, uint32_t noteVolume)
|
||||
{
|
||||
noteVolume = ((ulong)channelVolume * channelExpression * noteVolume) / (127*127);
|
||||
noteVolume = ((uint64_t)channelVolume * channelExpression * noteVolume) / (127*127);
|
||||
if (noteVolume > 127)
|
||||
return 127;
|
||||
else
|
||||
return noteVolume;
|
||||
}
|
||||
|
||||
int musicBlock::occupyChannel(uint slot, uint channel,
|
||||
int note, int volume, struct OP2instrEntry *instrument, uchar secondary)
|
||||
int musicBlock::occupyChannel(uint32_t slot, uint32_t channel,
|
||||
int note, int volume, struct OP2instrEntry *instrument, uint8_t secondary)
|
||||
{
|
||||
struct OPL2instrument *instr;
|
||||
struct channelEntry *ch = &channels[slot];
|
||||
|
@ -142,7 +142,7 @@ int musicBlock::occupyChannel(uint slot, uint channel,
|
|||
return slot;
|
||||
}
|
||||
|
||||
int musicBlock::releaseChannel(uint slot, uint killed)
|
||||
int musicBlock::releaseChannel(uint32_t slot, uint32_t killed)
|
||||
{
|
||||
struct channelEntry *ch = &channels[slot];
|
||||
writeFrequency(slot, ch->realnote, ch->pitch, 0);
|
||||
|
@ -157,10 +157,10 @@ int musicBlock::releaseChannel(uint slot, uint killed)
|
|||
return slot;
|
||||
}
|
||||
|
||||
int musicBlock::releaseSustain(uint channel)
|
||||
int musicBlock::releaseSustain(uint32_t channel)
|
||||
{
|
||||
uint i;
|
||||
uint id = channel;
|
||||
uint32_t i;
|
||||
uint32_t id = channel;
|
||||
|
||||
for(i = 0; i < io->OPLchannels; i++)
|
||||
{
|
||||
|
@ -170,16 +170,16 @@ int musicBlock::releaseSustain(uint channel)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int musicBlock::findFreeChannel(uint flag, uint channel, uchar note)
|
||||
int musicBlock::findFreeChannel(uint32_t flag, uint32_t channel, uint8_t note)
|
||||
{
|
||||
uint i;
|
||||
uint32_t i;
|
||||
|
||||
ulong bestfit = 0;
|
||||
uint bestvoice = 0;
|
||||
uint32_t bestfit = 0;
|
||||
uint32_t bestvoice = 0;
|
||||
|
||||
for (i = 0; i < io->OPLchannels; ++i)
|
||||
{
|
||||
ulong magic;
|
||||
uint32_t magic;
|
||||
|
||||
magic = ((channels[i].flags & CH_FREE) << 24) |
|
||||
((channels[i].note == note &&
|
||||
|
@ -200,9 +200,9 @@ int musicBlock::findFreeChannel(uint flag, uint channel, uchar note)
|
|||
return bestvoice;
|
||||
}
|
||||
|
||||
struct OP2instrEntry *musicBlock::getInstrument(uint channel, uchar note)
|
||||
struct OP2instrEntry *musicBlock::getInstrument(uint32_t channel, uint8_t note)
|
||||
{
|
||||
uint instrnumber;
|
||||
uint32_t instrnumber;
|
||||
|
||||
if (channel == PERCUSSION)
|
||||
{
|
||||
|
@ -225,7 +225,7 @@ struct OP2instrEntry *musicBlock::getInstrument(uint channel, uchar note)
|
|||
// code 1: play note
|
||||
CVAR (Bool, opl_singlevoice, 0, 0)
|
||||
|
||||
void musicBlock::OPLplayNote(uint channel, uchar note, int volume)
|
||||
void musicBlock::OPLplayNote(uint32_t channel, uint8_t note, int volume)
|
||||
{
|
||||
int i;
|
||||
struct OP2instrEntry *instr;
|
||||
|
@ -251,11 +251,11 @@ void musicBlock::OPLplayNote(uint channel, uchar note, int volume)
|
|||
}
|
||||
|
||||
// code 0: release note
|
||||
void musicBlock::OPLreleaseNote(uint channel, uchar note)
|
||||
void musicBlock::OPLreleaseNote(uint32_t channel, uint8_t note)
|
||||
{
|
||||
uint i;
|
||||
uint id = channel;
|
||||
uint sustain = driverdata.channelSustain[channel];
|
||||
uint32_t i;
|
||||
uint32_t id = channel;
|
||||
uint32_t sustain = driverdata.channelSustain[channel];
|
||||
|
||||
for(i = 0; i < io->OPLchannels; i++)
|
||||
{
|
||||
|
@ -270,10 +270,10 @@ void musicBlock::OPLreleaseNote(uint channel, uchar note)
|
|||
}
|
||||
|
||||
// code 2: change pitch wheel (bender)
|
||||
void musicBlock::OPLpitchWheel(uint channel, int pitch)
|
||||
void musicBlock::OPLpitchWheel(uint32_t channel, int pitch)
|
||||
{
|
||||
uint i;
|
||||
uint id = channel;
|
||||
uint32_t i;
|
||||
uint32_t id = channel;
|
||||
|
||||
// Convert pitch from 14-bit to 7-bit, then scale it, since the player
|
||||
// code only understands sensitivities of 2 semitones.
|
||||
|
@ -292,10 +292,10 @@ void musicBlock::OPLpitchWheel(uint channel, int pitch)
|
|||
}
|
||||
|
||||
// code 4: change control
|
||||
void musicBlock::OPLchangeControl(uint channel, uchar controller, int value)
|
||||
void musicBlock::OPLchangeControl(uint32_t channel, uint8_t controller, int value)
|
||||
{
|
||||
uint i;
|
||||
uint id = channel;
|
||||
uint32_t i;
|
||||
uint32_t id = channel;
|
||||
|
||||
switch (controller)
|
||||
{
|
||||
|
@ -310,7 +310,7 @@ void musicBlock::OPLchangeControl(uint channel, uchar controller, int value)
|
|||
struct channelEntry *ch = &channels[i];
|
||||
if (ch->channel == id)
|
||||
{
|
||||
uchar flags = ch->flags;
|
||||
uint8_t flags = ch->flags;
|
||||
ch->time = MLtime;
|
||||
if (value >= MOD_MIN)
|
||||
{
|
||||
|
@ -418,7 +418,7 @@ void musicBlock::OPLchangeControl(uint channel, uchar controller, int value)
|
|||
}
|
||||
}
|
||||
|
||||
void musicBlock::OPLresetControllers(uint chan, int vol)
|
||||
void musicBlock::OPLresetControllers(uint32_t chan, int vol)
|
||||
{
|
||||
driverdata.channelVolume[chan] = vol;
|
||||
driverdata.channelExpression[chan] = 127;
|
||||
|
@ -429,14 +429,14 @@ void musicBlock::OPLresetControllers(uint chan, int vol)
|
|||
driverdata.channelPitchSens[chan] = 200;
|
||||
}
|
||||
|
||||
void musicBlock::OPLprogramChange(uint channel, int value)
|
||||
void musicBlock::OPLprogramChange(uint32_t channel, int value)
|
||||
{
|
||||
driverdata.channelInstr[channel] = value;
|
||||
}
|
||||
|
||||
void musicBlock::OPLplayMusic(int vol)
|
||||
{
|
||||
uint i;
|
||||
uint32_t i;
|
||||
|
||||
for (i = 0; i < CHANNELS; i++)
|
||||
{
|
||||
|
@ -446,7 +446,7 @@ void musicBlock::OPLplayMusic(int vol)
|
|||
|
||||
void musicBlock::OPLstopMusic()
|
||||
{
|
||||
uint i;
|
||||
uint32_t i;
|
||||
for(i = 0; i < io->OPLchannels; i++)
|
||||
if (!(channels[i].flags & CH_FREE))
|
||||
releaseChannel(i, 1);
|
||||
|
@ -454,10 +454,10 @@ void musicBlock::OPLstopMusic()
|
|||
|
||||
int musicBlock::OPLloadBank (FileReader &data)
|
||||
{
|
||||
static const uchar masterhdr[8] = { '#','O','P','L','_','I','I','#' };
|
||||
static const uint8_t masterhdr[8] = { '#','O','P','L','_','I','I','#' };
|
||||
struct OP2instrEntry *instruments;
|
||||
|
||||
uchar filehdr[8];
|
||||
uint8_t filehdr[8];
|
||||
|
||||
data.Read (filehdr, 8);
|
||||
if (memcmp(filehdr, masterhdr, 8))
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
* Oct-30-1994 V1.40 V.Arnost
|
||||
* Added BLASTER variable parsing
|
||||
* Apr-14-1995 V1.50 V.Arnost
|
||||
* Some declarations moved from adlib.h to deftypes.h
|
||||
* Some declarations moved from adlib.h to doomtype.h
|
||||
* Jul-22-1995 V1.60 V.Arnost
|
||||
* Ported to Watcom C
|
||||
* Simplified WriteChannel() and WriteValue()
|
||||
|
@ -63,7 +63,7 @@ void OPLio::WriteDelay(int ticks)
|
|||
{
|
||||
}
|
||||
|
||||
void OPLio::OPLwriteReg(int which, uint reg, uchar data)
|
||||
void OPLio::OPLwriteReg(int which, uint32_t reg, uint8_t data)
|
||||
{
|
||||
if (IsOPL3)
|
||||
{
|
||||
|
@ -80,13 +80,13 @@ void OPLio::OPLwriteReg(int which, uint reg, uchar data)
|
|||
* Write to an operator pair. To be used for register bases of 0x20, 0x40,
|
||||
* 0x60, 0x80 and 0xE0.
|
||||
*/
|
||||
void OPLio::OPLwriteChannel(uint regbase, uint channel, uchar data1, uchar data2)
|
||||
void OPLio::OPLwriteChannel(uint32_t regbase, uint32_t channel, uint8_t data1, uint8_t data2)
|
||||
{
|
||||
static const uint op_num[OPL2CHANNELS] = {
|
||||
static const uint32_t op_num[OPL2CHANNELS] = {
|
||||
0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12};
|
||||
|
||||
uint which = channel / OPL2CHANNELS;
|
||||
uint reg = regbase + op_num[channel % OPL2CHANNELS];
|
||||
uint32_t which = channel / OPL2CHANNELS;
|
||||
uint32_t reg = regbase + op_num[channel % OPL2CHANNELS];
|
||||
OPLwriteReg (which, reg, data1);
|
||||
OPLwriteReg (which, reg+3, data2);
|
||||
}
|
||||
|
@ -95,10 +95,10 @@ void OPLio::OPLwriteChannel(uint regbase, uint channel, uchar data1, uchar data2
|
|||
* Write to channel a single value. To be used for register bases of
|
||||
* 0xA0, 0xB0 and 0xC0.
|
||||
*/
|
||||
void OPLio::OPLwriteValue(uint regbase, uint channel, uchar value)
|
||||
void OPLio::OPLwriteValue(uint32_t regbase, uint32_t channel, uint8_t value)
|
||||
{
|
||||
uint which = channel / OPL2CHANNELS;
|
||||
uint reg = regbase + (channel % OPL2CHANNELS);
|
||||
uint32_t which = channel / OPL2CHANNELS;
|
||||
uint32_t reg = regbase + (channel % OPL2CHANNELS);
|
||||
OPLwriteReg (which, reg, value);
|
||||
}
|
||||
|
||||
|
@ -174,7 +174,7 @@ static WORD frequencies[] =
|
|||
* That last byte in the table doesn't look right, either, but that's what
|
||||
* it really is.
|
||||
*/
|
||||
void OPLio::OPLwriteFreq(uint channel, uint note, uint pitch, uint keyon)
|
||||
void OPLio::OPLwriteFreq(uint32_t channel, uint32_t note, uint32_t pitch, uint32_t keyon)
|
||||
{
|
||||
int octave = 0;
|
||||
int j = (note << 5) + pitch;
|
||||
|
@ -202,9 +202,9 @@ void OPLio::OPLwriteFreq(uint channel, uint note, uint pitch, uint keyon)
|
|||
/*
|
||||
* Adjust volume value (register 0x40)
|
||||
*/
|
||||
inline uint OPLio::OPLconvertVolume(uint data, uint volume)
|
||||
inline uint32_t OPLio::OPLconvertVolume(uint32_t data, uint32_t volume)
|
||||
{
|
||||
static uchar volumetable[128] = {
|
||||
static uint8_t volumetable[128] = {
|
||||
0, 1, 3, 5, 6, 8, 10, 11,
|
||||
13, 14, 16, 17, 19, 20, 22, 23,
|
||||
25, 26, 27, 29, 30, 32, 33, 34,
|
||||
|
@ -223,11 +223,11 @@ inline uint OPLio::OPLconvertVolume(uint data, uint volume)
|
|||
124, 124, 125, 125, 126, 126, 127, 127};
|
||||
|
||||
return 0x3F - (((0x3F - data) *
|
||||
(uint)volumetable[volume <= 127 ? volume : 127]) >> 7);
|
||||
(uint32_t)volumetable[volume <= 127 ? volume : 127]) >> 7);
|
||||
|
||||
}
|
||||
|
||||
uint OPLio::OPLpanVolume(uint volume, int pan)
|
||||
uint32_t OPLio::OPLpanVolume(uint32_t volume, int pan)
|
||||
{
|
||||
if (pan >= 0)
|
||||
return volume;
|
||||
|
@ -238,7 +238,7 @@ uint OPLio::OPLpanVolume(uint volume, int pan)
|
|||
/*
|
||||
* Write volume data to a channel
|
||||
*/
|
||||
void OPLio::OPLwriteVolume(uint channel, struct OPL2instrument *instr, uint volume)
|
||||
void OPLio::OPLwriteVolume(uint32_t channel, struct OPL2instrument *instr, uint32_t volume)
|
||||
{
|
||||
if (instr != 0)
|
||||
{
|
||||
|
@ -251,11 +251,11 @@ void OPLio::OPLwriteVolume(uint channel, struct OPL2instrument *instr, uint volu
|
|||
/*
|
||||
* Write pan (balance) data to a channel
|
||||
*/
|
||||
void OPLio::OPLwritePan(uint channel, struct OPL2instrument *instr, int pan)
|
||||
void OPLio::OPLwritePan(uint32_t channel, struct OPL2instrument *instr, int pan)
|
||||
{
|
||||
if (instr != 0)
|
||||
{
|
||||
uchar bits;
|
||||
uint8_t bits;
|
||||
if (pan < -36) bits = 0x10; // left
|
||||
else if (pan > 36) bits = 0x20; // right
|
||||
else bits = 0x30; // both
|
||||
|
@ -292,7 +292,7 @@ void OPLio::OPLwritePan(uint channel, struct OPL2instrument *instr, int pan)
|
|||
* data[5] data[12] reg. 0x40 - output level (bottom 6 bits only)
|
||||
* data[6] reg. 0xC0 - feedback/AM-FM (both operators)
|
||||
*/
|
||||
void OPLio::OPLwriteInstrument(uint channel, struct OPL2instrument *instr)
|
||||
void OPLio::OPLwriteInstrument(uint32_t channel, struct OPL2instrument *instr)
|
||||
{
|
||||
OPLwriteChannel(0x40, channel, 0x3F, 0x3F); // no volume
|
||||
OPLwriteChannel(0x20, channel, instr->trem_vibr_1, instr->trem_vibr_2);
|
||||
|
@ -307,7 +307,7 @@ void OPLio::OPLwriteInstrument(uint channel, struct OPL2instrument *instr)
|
|||
*/
|
||||
void OPLio::OPLshutup(void)
|
||||
{
|
||||
uint i;
|
||||
uint32_t i;
|
||||
|
||||
for(i = 0; i < OPLchannels; i++)
|
||||
{
|
||||
|
@ -321,10 +321,10 @@ void OPLio::OPLshutup(void)
|
|||
/*
|
||||
* Initialize hardware upon startup
|
||||
*/
|
||||
int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3)
|
||||
int OPLio::OPLinit(uint32_t numchips, bool stereo, bool initopl3)
|
||||
{
|
||||
assert(numchips >= 1 && numchips <= countof(chips));
|
||||
uint i;
|
||||
uint32_t i;
|
||||
IsOPL3 = (current_opl_core == 1 || current_opl_core == 2 || current_opl_core == 3);
|
||||
|
||||
memset(chips, 0, sizeof(chips));
|
||||
|
@ -349,7 +349,7 @@ int OPLio::OPLinit(uint numchips, bool stereo, bool initopl3)
|
|||
|
||||
void OPLio::OPLwriteInitState(bool initopl3)
|
||||
{
|
||||
for (uint i = 0; i < NumChips; ++i)
|
||||
for (uint32_t i = 0; i < NumChips; ++i)
|
||||
{
|
||||
int chip = i << (int)IsOPL3;
|
||||
if (IsOPL3 && initopl3)
|
||||
|
|
|
@ -289,7 +289,7 @@ FString OPLMIDIDevice::GetStats()
|
|||
{
|
||||
FString out;
|
||||
char star[3] = { TEXTCOLOR_ESCAPE, 'A', '*' };
|
||||
for (uint i = 0; i < io->OPLchannels; ++i)
|
||||
for (uint32_t i = 0; i < io->OPLchannels; ++i)
|
||||
{
|
||||
if (channels[i].flags & CH_FREE)
|
||||
{
|
||||
|
|
|
@ -336,7 +336,7 @@ DiskWriterIO::~DiskWriterIO()
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
int DiskWriterIO::OPLinit(uint numchips, bool, bool initopl3)
|
||||
int DiskWriterIO::OPLinit(uint32_t numchips, bool, bool initopl3)
|
||||
{
|
||||
FILE *file = fopen(Filename, "wb");
|
||||
if (file == NULL)
|
||||
|
|
|
@ -76,7 +76,7 @@ Voice-mail (Czech language only, not recommended; weekends only):
|
|||
#define __MUSLIB_H_
|
||||
|
||||
#ifndef __DEFTYPES_H_
|
||||
#include "deftypes.h"
|
||||
#include "doomtype.h"
|
||||
#endif
|
||||
|
||||
class FileReader;
|
||||
|
@ -119,7 +119,7 @@ struct OPL2instrument {
|
|||
/*0B*/ BYTE scale_2; /* OP 2: key scale level */
|
||||
/*0C*/ BYTE level_2; /* OP 2: output level */
|
||||
/*0D*/ BYTE unused;
|
||||
/*0E*/ sshort basenote; /* base note offset */
|
||||
/*0E*/ int16_t basenote; /* base note offset */
|
||||
};
|
||||
|
||||
/* OP2 instrument file entry */
|
||||
|
@ -152,41 +152,41 @@ struct OP2instrEntry {
|
|||
#define CH_FREE 0x80
|
||||
|
||||
struct OPLdata {
|
||||
uint channelInstr[CHANNELS]; // instrument #
|
||||
uchar channelVolume[CHANNELS]; // volume
|
||||
uchar channelLastVolume[CHANNELS]; // last volume
|
||||
schar channelPan[CHANNELS]; // pan, 0=normal
|
||||
schar channelPitch[CHANNELS]; // pitch wheel, 64=normal
|
||||
uchar channelSustain[CHANNELS]; // sustain pedal value
|
||||
uchar channelModulation[CHANNELS]; // modulation pot value
|
||||
ushort channelPitchSens[CHANNELS]; // pitch sensitivity, 2=default
|
||||
ushort channelRPN[CHANNELS]; // RPN number for data entry
|
||||
uchar channelExpression[CHANNELS]; // expression
|
||||
uint32_t channelInstr[CHANNELS]; // instrument #
|
||||
uint8_t channelVolume[CHANNELS]; // volume
|
||||
uint8_t channelLastVolume[CHANNELS]; // last volume
|
||||
int8_t channelPan[CHANNELS]; // pan, 0=normal
|
||||
int8_t channelPitch[CHANNELS]; // pitch wheel, 64=normal
|
||||
uint8_t channelSustain[CHANNELS]; // sustain pedal value
|
||||
uint8_t channelModulation[CHANNELS]; // modulation pot value
|
||||
uint16_t channelPitchSens[CHANNELS]; // pitch sensitivity, 2=default
|
||||
uint16_t channelRPN[CHANNELS]; // RPN number for data entry
|
||||
uint8_t channelExpression[CHANNELS]; // expression
|
||||
};
|
||||
|
||||
struct OPLio {
|
||||
virtual ~OPLio();
|
||||
|
||||
void OPLwriteChannel(uint regbase, uint channel, uchar data1, uchar data2);
|
||||
void OPLwriteValue(uint regbase, uint channel, uchar value);
|
||||
void OPLwriteFreq(uint channel, uint freq, uint octave, uint keyon);
|
||||
uint OPLconvertVolume(uint data, uint volume);
|
||||
uint OPLpanVolume(uint volume, int pan);
|
||||
void OPLwriteVolume(uint channel, struct OPL2instrument *instr, uint volume);
|
||||
void OPLwritePan(uint channel, struct OPL2instrument *instr, int pan);
|
||||
void OPLwriteInstrument(uint channel, struct OPL2instrument *instr);
|
||||
void OPLwriteChannel(uint32_t regbase, uint32_t channel, uint8_t data1, uint8_t data2);
|
||||
void OPLwriteValue(uint32_t regbase, uint32_t channel, uint8_t value);
|
||||
void OPLwriteFreq(uint32_t channel, uint32_t freq, uint32_t octave, uint32_t keyon);
|
||||
uint32_t OPLconvertVolume(uint32_t data, uint32_t volume);
|
||||
uint32_t OPLpanVolume(uint32_t volume, int pan);
|
||||
void OPLwriteVolume(uint32_t channel, struct OPL2instrument *instr, uint32_t volume);
|
||||
void OPLwritePan(uint32_t channel, struct OPL2instrument *instr, int pan);
|
||||
void OPLwriteInstrument(uint32_t channel, struct OPL2instrument *instr);
|
||||
void OPLshutup(void);
|
||||
void OPLwriteInitState(bool initopl3);
|
||||
|
||||
virtual int OPLinit(uint numchips, bool stereo=false, bool initopl3=false);
|
||||
virtual int OPLinit(uint32_t numchips, bool stereo=false, bool initopl3=false);
|
||||
virtual void OPLdeinit(void);
|
||||
virtual void OPLwriteReg(int which, uint reg, uchar data);
|
||||
virtual void OPLwriteReg(int which, uint32_t reg, uint8_t data);
|
||||
virtual void SetClockRate(double samples_per_tick);
|
||||
virtual void WriteDelay(int ticks);
|
||||
|
||||
class OPLEmul *chips[MAXOPL2CHIPS];
|
||||
uint OPLchannels;
|
||||
uint NumChips;
|
||||
uint32_t OPLchannels;
|
||||
uint32_t NumChips;
|
||||
bool IsOPL3;
|
||||
};
|
||||
|
||||
|
@ -195,7 +195,7 @@ struct DiskWriterIO : public OPLio
|
|||
DiskWriterIO(const char *filename);
|
||||
~DiskWriterIO();
|
||||
|
||||
int OPLinit(uint numchips, bool notused, bool initopl3);
|
||||
int OPLinit(uint32_t numchips, bool notused, bool initopl3);
|
||||
void SetClockRate(double samples_per_tick);
|
||||
void WriteDelay(int ticks);
|
||||
|
||||
|
@ -214,14 +214,14 @@ struct musicBlock {
|
|||
|
||||
struct OP2instrEntry *OPLinstruments;
|
||||
|
||||
ulong MLtime;
|
||||
uint32_t MLtime;
|
||||
|
||||
void OPLplayNote(uint channel, uchar note, int volume);
|
||||
void OPLreleaseNote(uint channel, uchar note);
|
||||
void OPLpitchWheel(uint channel, int pitch);
|
||||
void OPLchangeControl(uint channel, uchar controller, int value);
|
||||
void OPLprogramChange(uint channel, int value);
|
||||
void OPLresetControllers(uint channel, int vol);
|
||||
void OPLplayNote(uint32_t channel, uint8_t note, int volume);
|
||||
void OPLreleaseNote(uint32_t channel, uint8_t note);
|
||||
void OPLpitchWheel(uint32_t channel, int pitch);
|
||||
void OPLchangeControl(uint32_t channel, uint8_t controller, int value);
|
||||
void OPLprogramChange(uint32_t channel, int value);
|
||||
void OPLresetControllers(uint32_t channel, int vol);
|
||||
void OPLplayMusic(int vol);
|
||||
void OPLstopMusic();
|
||||
|
||||
|
@ -230,27 +230,27 @@ struct musicBlock {
|
|||
protected:
|
||||
/* OPL channel (voice) data */
|
||||
struct channelEntry {
|
||||
uchar channel; /* MUS channel number */
|
||||
uchar note; /* note number */
|
||||
uchar flags; /* see CH_xxx below */
|
||||
uchar realnote; /* adjusted note number */
|
||||
schar finetune; /* frequency fine-tune */
|
||||
sint pitch; /* pitch-wheel value */
|
||||
uint volume; /* note volume */
|
||||
uint realvolume; /* adjusted note volume */
|
||||
uint8_t channel; /* MUS channel number */
|
||||
uint8_t note; /* note number */
|
||||
uint8_t flags; /* see CH_xxx below */
|
||||
uint8_t realnote; /* adjusted note number */
|
||||
int8_t finetune; /* frequency fine-tune */
|
||||
int pitch; /* pitch-wheel value */
|
||||
uint32_t volume; /* note volume */
|
||||
uint32_t realvolume; /* adjusted note volume */
|
||||
struct OPL2instrument *instr; /* current instrument */
|
||||
ulong time; /* note start time */
|
||||
uint32_t time; /* note start time */
|
||||
} channels[MAXCHANNELS];
|
||||
|
||||
void writeFrequency(uint slot, uint note, int pitch, uint keyOn);
|
||||
void writeModulation(uint slot, struct OPL2instrument *instr, int state);
|
||||
uint calcVolume(uint channelVolume, uint channelExpression, uint noteVolume);
|
||||
int occupyChannel(uint slot, uint channel,
|
||||
int note, int volume, struct OP2instrEntry *instrument, uchar secondary);
|
||||
int releaseChannel(uint slot, uint killed);
|
||||
int releaseSustain(uint channel);
|
||||
int findFreeChannel(uint flag, uint channel, uchar note);
|
||||
struct OP2instrEntry *getInstrument(uint channel, uchar note);
|
||||
void writeFrequency(uint32_t slot, uint32_t note, int pitch, uint32_t keyOn);
|
||||
void writeModulation(uint32_t slot, struct OPL2instrument *instr, int state);
|
||||
uint32_t calcVolume(uint32_t channelVolume, uint32_t channelExpression, uint32_t noteVolume);
|
||||
int occupyChannel(uint32_t slot, uint32_t channel,
|
||||
int note, int volume, struct OP2instrEntry *instrument, uint8_t secondary);
|
||||
int releaseChannel(uint32_t slot, uint32_t killed);
|
||||
int releaseSustain(uint32_t channel);
|
||||
int findFreeChannel(uint32_t flag, uint32_t channel, uint8_t note);
|
||||
struct OP2instrEntry *getInstrument(uint32_t channel, uint8_t note);
|
||||
|
||||
friend class Stat_opl;
|
||||
|
||||
|
|
|
@ -856,7 +856,8 @@ void P_Spawn3DFloors (void)
|
|||
{
|
||||
case ExtraFloor_LightOnly:
|
||||
if (line.args[1] < 0 || line.args[1] > 2) line.args[1] = 0;
|
||||
P_Set3DFloor(&line, 3, flagvals[line.args[1]], 0);
|
||||
if (line.args[0] != 0)
|
||||
P_Set3DFloor(&line, 3, flagvals[line.args[1]], 0);
|
||||
break;
|
||||
|
||||
case Sector_Set3DFloor:
|
||||
|
@ -875,7 +876,8 @@ void P_Spawn3DFloors (void)
|
|||
line.args[4]=0;
|
||||
}
|
||||
}
|
||||
P_Set3DFloor(&line, line.args[1]&~8, line.args[2], line.args[3]);
|
||||
if (line.args[0] != 0)
|
||||
P_Set3DFloor(&line, line.args[1]&~8, line.args[2], line.args[3]);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -1097,7 +1097,7 @@ public:
|
|||
{
|
||||
ld->alpha = 0.75;
|
||||
}
|
||||
if (strifetrans2 && ld->alpha == OPAQUE)
|
||||
if (strifetrans2 && ld->alpha == 1.)
|
||||
{
|
||||
ld->alpha = 0.25;
|
||||
}
|
||||
|
|
|
@ -6368,11 +6368,8 @@ ExpEmit FxClassDefaults::Emit(VMFunctionBuilder *build)
|
|||
//==========================================================================
|
||||
|
||||
FxGlobalVariable::FxGlobalVariable(PField* mem, const FScriptPosition &pos)
|
||||
: FxExpression(EFX_GlobalVariable, pos)
|
||||
: FxMemberBase(EFX_GlobalVariable, mem, pos)
|
||||
{
|
||||
membervar = mem;
|
||||
AddressRequested = false;
|
||||
AddressWritable = true; // must be true unless classx tells us otherwise if requested.
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -6548,11 +6545,8 @@ ExpEmit FxCVar::Emit(VMFunctionBuilder *build)
|
|||
//==========================================================================
|
||||
|
||||
FxStackVariable::FxStackVariable(PType *type, int offset, const FScriptPosition &pos)
|
||||
: FxExpression(EFX_StackVariable, pos)
|
||||
: FxMemberBase(EFX_StackVariable, new PField(NAME_None, type, 0, offset), pos)
|
||||
{
|
||||
membervar = new PField(NAME_None, type, 0, offset);
|
||||
AddressRequested = false;
|
||||
AddressWritable = true; // must be true unless classx tells us otherwise if requested.
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -6651,14 +6645,16 @@ ExpEmit FxStackVariable::Emit(VMFunctionBuilder *build)
|
|||
//
|
||||
//
|
||||
//==========================================================================
|
||||
FxMemberBase::FxMemberBase(EFxType type, PField *f, const FScriptPosition &p)
|
||||
:FxExpression(type, p), membervar(f)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
FxStructMember::FxStructMember(FxExpression *x, PField* mem, const FScriptPosition &pos)
|
||||
: FxExpression(EFX_StructMember, pos)
|
||||
: FxMemberBase(EFX_StructMember, mem, pos)
|
||||
{
|
||||
classx = x;
|
||||
membervar = mem;
|
||||
AddressRequested = false;
|
||||
AddressWritable = true; // must be true unless classx tells us otherwise if requested.
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
@ -6730,35 +6726,13 @@ FxExpression *FxStructMember::Resolve(FCompileContext &ctx)
|
|||
else if (classx->ValueType->IsKindOf(RUNTIME_CLASS(PStruct)))
|
||||
{
|
||||
// if this is a struct within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset.
|
||||
if (classx->ExprType == EFX_ClassMember || classx->ExprType == EFX_StructMember)
|
||||
if (classx->ExprType == EFX_ClassMember || classx->ExprType == EFX_StructMember || classx->ExprType == EFX_GlobalVariable || classx->ExprType == EFX_StackVariable)
|
||||
{
|
||||
auto parentfield = static_cast<FxStructMember *>(classx)->membervar;
|
||||
auto parentfield = static_cast<FxMemberBase *>(classx)->membervar;
|
||||
// PFields are garbage collected so this will be automatically taken care of later.
|
||||
auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset);
|
||||
newfield->BitValue = membervar->BitValue;
|
||||
static_cast<FxStructMember *>(classx)->membervar = newfield;
|
||||
classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
|
||||
auto x = classx->Resolve(ctx);
|
||||
classx = nullptr;
|
||||
return x;
|
||||
}
|
||||
else if (classx->ExprType == EFX_GlobalVariable)
|
||||
{
|
||||
auto parentfield = static_cast<FxGlobalVariable *>(classx)->membervar;
|
||||
auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset);
|
||||
newfield->BitValue = membervar->BitValue;
|
||||
static_cast<FxGlobalVariable *>(classx)->membervar = newfield;
|
||||
classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
|
||||
auto x = classx->Resolve(ctx);
|
||||
classx = nullptr;
|
||||
return x;
|
||||
}
|
||||
else if (classx->ExprType == EFX_StackVariable)
|
||||
{
|
||||
auto parentfield = static_cast<FxStackVariable *>(classx)->membervar;
|
||||
auto newfield = new PField(membervar->SymbolName, membervar->Type, membervar->Flags | parentfield->Flags, membervar->Offset + parentfield->Offset);
|
||||
newfield->BitValue = membervar->BitValue;
|
||||
static_cast<FxStackVariable *>(classx)->ReplaceField(newfield);
|
||||
static_cast<FxMemberBase *>(classx)->membervar = newfield;
|
||||
classx->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
|
||||
auto x = classx->Resolve(ctx);
|
||||
classx = nullptr;
|
||||
|
@ -6946,33 +6920,41 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
PArray *arraytype = dyn_cast<PArray>(Array->ValueType);
|
||||
if (arraytype == nullptr)
|
||||
PArray *arraytype = nullptr;
|
||||
PType *elementtype = nullptr;
|
||||
if (Array->IsDynamicArray())
|
||||
{
|
||||
// Check if we got a pointer to an array. Some native data structures (like the line list in sectors) use this.
|
||||
PPointer *ptype = dyn_cast<PPointer>(Array->ValueType);
|
||||
if (ptype == nullptr || !ptype->PointedType->IsKindOf(RUNTIME_CLASS(PArray)))
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays.");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
arraytype = static_cast<PArray*>(ptype->PointedType);
|
||||
PDynArray *darraytype = static_cast<PDynArray*>(Array->ValueType);
|
||||
elementtype = darraytype->ElementType;
|
||||
Array->ValueType = NewPointer(NewResizableArray(elementtype)); // change type so that this can use the code for resizable arrays unchanged.
|
||||
arrayispointer = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
arraytype = dyn_cast<PArray>(Array->ValueType);
|
||||
if (arraytype == nullptr)
|
||||
{
|
||||
// Check if we got a pointer to an array. Some native data structures (like the line list in sectors) use this.
|
||||
PPointer *ptype = dyn_cast<PPointer>(Array->ValueType);
|
||||
if (ptype == nullptr || !ptype->PointedType->IsKindOf(RUNTIME_CLASS(PArray)))
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "'[]' can only be used with arrays.");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
arraytype = static_cast<PArray*>(ptype->PointedType);
|
||||
arrayispointer = true;
|
||||
}
|
||||
elementtype = arraytype->ElementType;
|
||||
}
|
||||
|
||||
if (Array->IsResizableArray())
|
||||
{
|
||||
// if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset.
|
||||
if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember)
|
||||
if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember || Array->ExprType == EFX_GlobalVariable || Array->ExprType == EFX_StackVariable)
|
||||
{
|
||||
auto parentfield = static_cast<FxStructMember *>(Array)->membervar;
|
||||
SizeAddr = parentfield->Offset + parentfield->Type->Align;
|
||||
}
|
||||
else if (Array->ExprType == EFX_GlobalVariable)
|
||||
{
|
||||
auto parentfield = static_cast<FxGlobalVariable *>(Array)->membervar;
|
||||
SizeAddr = parentfield->Offset + parentfield->Type->Align;
|
||||
auto parentfield = static_cast<FxMemberBase *>(Array)->membervar;
|
||||
SizeAddr = parentfield->Offset + sizeof(void*);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -6981,54 +6963,32 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx)
|
|||
return nullptr;
|
||||
}
|
||||
}
|
||||
else if (index->isConstant())
|
||||
// constant indices can only be resolved at compile time for statically sized arrays.
|
||||
else if (index->isConstant() && arraytype != nullptr && !arrayispointer)
|
||||
{
|
||||
unsigned indexval = static_cast<FxConstant *>(index)->GetValue().GetInt();
|
||||
if (indexval >= arraytype->ElementCount && !Array->IsResizableArray())
|
||||
if (indexval >= arraytype->ElementCount)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Array index out of bounds");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!arrayispointer)
|
||||
// if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset.
|
||||
if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember || Array->ExprType == EFX_GlobalVariable || Array->ExprType == EFX_StackVariable)
|
||||
{
|
||||
// if this is an array within a class or another struct we can simplify the expression by creating a new PField with a cumulative offset.
|
||||
if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember)
|
||||
{
|
||||
auto parentfield = static_cast<FxStructMember *>(Array)->membervar;
|
||||
// PFields are garbage collected so this will be automatically taken care of later.
|
||||
auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset);
|
||||
static_cast<FxStructMember *>(Array)->membervar = newfield;
|
||||
Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
|
||||
auto x = Array->Resolve(ctx);
|
||||
Array = nullptr;
|
||||
return x;
|
||||
}
|
||||
else if (Array->ExprType == EFX_GlobalVariable)
|
||||
{
|
||||
auto parentfield = static_cast<FxGlobalVariable *>(Array)->membervar;
|
||||
auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset);
|
||||
static_cast<FxGlobalVariable *>(Array)->membervar = newfield;
|
||||
Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
|
||||
auto x = Array->Resolve(ctx);
|
||||
Array = nullptr;
|
||||
return x;
|
||||
}
|
||||
else if (Array->ExprType == EFX_StackVariable)
|
||||
{
|
||||
auto parentfield = static_cast<FxStackVariable *>(Array)->membervar;
|
||||
auto newfield = new PField(NAME_None, arraytype->ElementType, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset);
|
||||
static_cast<FxStackVariable *>(Array)->ReplaceField(newfield);
|
||||
Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
|
||||
auto x = Array->Resolve(ctx);
|
||||
Array = nullptr;
|
||||
return x;
|
||||
}
|
||||
auto parentfield = static_cast<FxMemberBase *>(Array)->membervar;
|
||||
// PFields are garbage collected so this will be automatically taken care of later.
|
||||
auto newfield = new PField(NAME_None, elementtype, parentfield->Flags, indexval * arraytype->ElementSize + parentfield->Offset);
|
||||
static_cast<FxMemberBase *>(Array)->membervar = newfield;
|
||||
Array->isresolved = false; // re-resolve the parent so it can also check if it can be optimized away.
|
||||
auto x = Array->Resolve(ctx);
|
||||
Array = nullptr;
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
ValueType = arraytype->ElementType;
|
||||
ValueType = elementtype;
|
||||
if (!Array->RequestAddress(ctx, &AddressWritable))
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Unable to dereference array.");
|
||||
|
@ -7067,17 +7027,8 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
|
|||
build->Emit(OP_LP, start.RegNum, arrayvar.RegNum, build->GetConstantInt(0));
|
||||
|
||||
auto f = new PField(NAME_None, TypeUInt32, 0, SizeAddr);
|
||||
if (Array->ExprType == EFX_ClassMember || Array->ExprType == EFX_StructMember)
|
||||
{
|
||||
static_cast<FxStructMember *>(Array)->membervar = f;
|
||||
static_cast<FxStructMember *>(Array)->AddressRequested = false;
|
||||
}
|
||||
else if (Array->ExprType == EFX_GlobalVariable)
|
||||
{
|
||||
static_cast<FxGlobalVariable *>(Array)->membervar = f;
|
||||
static_cast<FxGlobalVariable *>(Array)->AddressRequested = false;
|
||||
}
|
||||
|
||||
static_cast<FxMemberBase *>(Array)->membervar = f;
|
||||
static_cast<FxMemberBase *>(Array)->AddressRequested = false;
|
||||
Array->ValueType = TypeUInt32;
|
||||
bound = Array->Emit(build);
|
||||
}
|
||||
|
@ -7804,6 +7755,70 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
// same for String methods. It also uses a hidden struct type to define them.
|
||||
Self->ValueType = TypeStringStruct;
|
||||
}
|
||||
else if (Self->IsDynamicArray())
|
||||
{
|
||||
if (MethodName == NAME_Size)
|
||||
{
|
||||
FxExpression *x = new FxMemberIdentifier(Self, NAME_Size, ScriptPosition); // todo: obfuscate the name to prevent direct access.
|
||||
Self = nullptr;
|
||||
delete this;
|
||||
return x->Resolve(ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto elementType = static_cast<PDynArray*>(Self->ValueType)->ElementType;
|
||||
Self->ValueType = static_cast<PDynArray*>(Self->ValueType)->BackingType;
|
||||
// this requires some added type checks for the passed types.
|
||||
for (auto &a : ArgList)
|
||||
{
|
||||
a = a->Resolve(ctx);
|
||||
if (a == nullptr)
|
||||
{
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
if (a->IsDynamicArray())
|
||||
{
|
||||
// Copy and Move must turn their parameter into a pointer to the backing struct type.
|
||||
auto backingtype = static_cast<PDynArray*>(a->ValueType)->BackingType;
|
||||
if (elementType != static_cast<PDynArray*>(a->ValueType)->ElementType)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
bool writable;
|
||||
if (!a->RequestAddress(ctx, &writable))
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Unable to dereference array variable");
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
a->ValueType = NewPointer(backingtype);
|
||||
|
||||
// Also change the field's type so the code generator can work with this (actually this requires swapping out the entire field.)
|
||||
if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember || Self->ExprType == EFX_StackVariable)
|
||||
{
|
||||
auto member = static_cast<FxMemberBase*>(Self);
|
||||
auto newfield = new PField(NAME_None, backingtype, 0, member->membervar->Offset);
|
||||
member->membervar = newfield;
|
||||
}
|
||||
}
|
||||
else if (a->IsPointer() && Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)))
|
||||
{
|
||||
// the only case which must be checked up front is for pointer arrays receiving a new element.
|
||||
// Since there is only one native backing class it uses a neutral void pointer as its argument,
|
||||
// meaning that FxMemberFunctionCall is unable to do a proper check. So we have to do it here.
|
||||
if (a->ValueType != elementType)
|
||||
{
|
||||
ScriptPosition.Message(MSG_ERROR, "Type mismatch in function argument. Got %s, expected %s", a->ValueType->DescriptiveName(), elementType->DescriptiveName());
|
||||
delete this;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Self->IsArray())
|
||||
{
|
||||
if (MethodName == NAME_Size)
|
||||
|
@ -7826,19 +7841,9 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
|
|||
else
|
||||
{
|
||||
// Resizable arrays can only be defined in C code and they can only exist in pointer form to reduce their impact on the code generator.
|
||||
if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember)
|
||||
if (Self->ExprType == EFX_StructMember || Self->ExprType == EFX_ClassMember || Self->ExprType == EFX_GlobalVariable)
|
||||
{
|
||||
auto member = static_cast<FxStructMember*>(Self);
|
||||
auto newfield = new PField(NAME_None, TypeUInt32, VARF_ReadOnly, member->membervar->Offset + member->membervar->Type->Align); // the size is stored right behind the pointer.
|
||||
member->membervar = newfield;
|
||||
Self = nullptr;
|
||||
delete this;
|
||||
member->ValueType = TypeUInt32;
|
||||
return member;
|
||||
}
|
||||
else if (Self->ExprType == EFX_GlobalVariable)
|
||||
{
|
||||
auto member = static_cast<FxGlobalVariable*>(Self);
|
||||
auto member = static_cast<FxMemberBase*>(Self);
|
||||
auto newfield = new PField(NAME_None, TypeUInt32, VARF_ReadOnly, member->membervar->Offset + member->membervar->Type->Align); // the size is stored right behind the pointer.
|
||||
member->membervar = newfield;
|
||||
Self = nullptr;
|
||||
|
|
|
@ -333,6 +333,7 @@ public:
|
|||
bool IsObject() const { return ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && !ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)) && ValueType != TypeNullPtr && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PClass)); }
|
||||
bool IsArray() const { return ValueType->IsKindOf(RUNTIME_CLASS(PArray)) || (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PArray))); }
|
||||
bool IsResizableArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PPointer)) && static_cast<PPointer*>(ValueType)->PointedType->IsKindOf(RUNTIME_CLASS(PResizableArray))); } // can only exist in pointer form.
|
||||
bool IsDynamicArray() const { return (ValueType->IsKindOf(RUNTIME_CLASS(PDynArray))); }
|
||||
|
||||
virtual ExpEmit Emit(VMFunctionBuilder *build);
|
||||
void EmitStatement(VMFunctionBuilder *build);
|
||||
|
@ -1313,19 +1314,30 @@ public:
|
|||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxMemberBase
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxMemberBase : public FxExpression
|
||||
{
|
||||
public:
|
||||
PField *membervar;
|
||||
bool AddressRequested = false;
|
||||
bool AddressWritable = true;
|
||||
FxMemberBase(EFxType type, PField *f, const FScriptPosition &p);
|
||||
};
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxGlobalVariaböe
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxGlobalVariable : public FxExpression
|
||||
class FxGlobalVariable : public FxMemberBase
|
||||
{
|
||||
public:
|
||||
PField *membervar;
|
||||
bool AddressRequested;
|
||||
bool AddressWritable;
|
||||
|
||||
FxGlobalVariable(PField*, const FScriptPosition&);
|
||||
FxExpression *Resolve(FCompileContext&);
|
||||
bool RequestAddress(FCompileContext &ctx, bool *writable);
|
||||
|
@ -1342,19 +1354,17 @@ public:
|
|||
ExpEmit Emit(VMFunctionBuilder *build);
|
||||
};
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxClassMember
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxStructMember : public FxExpression
|
||||
class FxStructMember : public FxMemberBase
|
||||
{
|
||||
public:
|
||||
FxExpression *classx;
|
||||
PField *membervar;
|
||||
bool AddressRequested;
|
||||
bool AddressWritable;
|
||||
|
||||
FxStructMember(FxExpression*, PField*, const FScriptPosition&);
|
||||
~FxStructMember();
|
||||
|
@ -1402,13 +1412,9 @@ public:
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
class FxStackVariable : public FxExpression
|
||||
class FxStackVariable : public FxMemberBase
|
||||
{
|
||||
public:
|
||||
PField *membervar;
|
||||
bool AddressRequested;
|
||||
bool AddressWritable;
|
||||
|
||||
FxStackVariable(PType *type, int offset, const FScriptPosition&);
|
||||
~FxStackVariable();
|
||||
void ReplaceField(PField *newfield);
|
||||
|
|
|
@ -1136,4 +1136,51 @@ DEFINE_ACTION_FUNCTION(FStringStruct, AppendFormat)
|
|||
FString s = FStringFormat(param+1, defaultparam, numparam-1, ret, numret);
|
||||
(*self) += s;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FStringStruct, Mid)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||
PARAM_INT(ipos);
|
||||
PARAM_INT(ilen);
|
||||
// validate. we don't want to crash if someone passes negative values.
|
||||
// with size_t it's handled naturally I think, as it's unsigned, but not in ZScript.
|
||||
if (ipos < 0) ipos = 0;
|
||||
if (ilen < 0) ilen = 0;
|
||||
// convert to size_t to prevent overflows here
|
||||
size_t slen = self->Len();
|
||||
size_t pos = (size_t)ipos;
|
||||
size_t len = (size_t)ilen;
|
||||
if (pos > slen) pos = slen - 1;
|
||||
if (pos + len > slen)
|
||||
len = slen - pos;
|
||||
FString s = self->Mid(pos, len);
|
||||
ACTION_RETURN_STRING(s);
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FStringStruct, Len)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||
ACTION_RETURN_INT(self->Len());
|
||||
}
|
||||
|
||||
// CharAt and CharCodeAt is how JS does it, and JS is similar here in that it doesn't have char type as int.
|
||||
DEFINE_ACTION_FUNCTION(FStringStruct, CharAt)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||
PARAM_INT(pos);
|
||||
int slen = self->Len();
|
||||
if (pos < 0 || pos >= slen)
|
||||
ACTION_RETURN_STRING("");
|
||||
ACTION_RETURN_STRING(FString((*self)[pos]));
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(FStringStruct, CharCodeAt)
|
||||
{
|
||||
PARAM_SELF_STRUCT_PROLOGUE(FString);
|
||||
PARAM_INT(pos);
|
||||
int slen = self->Len();
|
||||
if (pos < 0 || pos >= slen)
|
||||
ACTION_RETURN_INT(0);
|
||||
ACTION_RETURN_INT((*self)[pos]);
|
||||
}
|
||||
|
|
|
@ -1358,9 +1358,16 @@ PType *ZCCCompiler::DetermineType(PType *outertype, ZCC_TreeNode *field, FName n
|
|||
case AST_DynArrayType:
|
||||
if (allowarraytypes)
|
||||
{
|
||||
Error(field, "%s: Dynamic array types not implemented yet", name.GetChars());
|
||||
auto atype = static_cast<ZCC_DynArrayType *>(ztype);
|
||||
retval = NewDynArray(DetermineType(outertype, field, name, atype->ElementType, false, false));
|
||||
auto ftype = DetermineType(outertype, field, name, atype->ElementType, false, true);
|
||||
if (ftype->GetRegType() == REGT_NIL || ftype->GetRegCount() > 1)
|
||||
{
|
||||
Error(field, "%s: Base type for dynamic array types nust be integral, but got %s", name.GetChars(), ftype->DescriptiveName());
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = NewDynArray(ftype);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -417,9 +417,14 @@ enum EPickStart
|
|||
// Although String is a builtin type, this is a convenient way to attach methods to it.
|
||||
struct StringStruct native
|
||||
{
|
||||
native void Replace(String pattern, String replacement);
|
||||
native static vararg String Format(String fmt, ...);
|
||||
native vararg void AppendFormat(String fmt, ...);
|
||||
|
||||
native void Replace(String pattern, String replacement);
|
||||
native String Mid(int pos = 0, int len = 2147483647);
|
||||
native int Len();
|
||||
native String CharAt(int pos);
|
||||
native int CharCodeAt(int pos);
|
||||
}
|
||||
|
||||
class Floor : Thinker native
|
||||
|
|
|
@ -156,7 +156,7 @@ class FastProjectile : Actor
|
|||
ExplodeMissile (NULL, NULL);
|
||||
return;
|
||||
}
|
||||
if (frac != (0, 0, 0) && ripcount <= 0)
|
||||
if (!(frac.xy ~== (0, 0)) && ripcount <= 0)
|
||||
{
|
||||
ripcount = count >> 3;
|
||||
|
||||
|
|
Loading…
Reference in a new issue