- removed all ZDoom dependencies from the OPL backend code.

This commit is contained in:
Christoph Oelckers 2019-09-26 18:15:23 +02:00
parent 2aa03e8e8a
commit 17eac1c57b
12 changed files with 286 additions and 41 deletions

View file

@ -140,6 +140,18 @@ protected:
// OPL dumper implementation of a MIDI output device ------------------------
struct DiskWriterIO : public OPLio
{
DiskWriterIO(const char* filename);
~DiskWriterIO();
int Init(uint32_t numchips, bool notused, bool initopl3);
void SetClockRate(double samples_per_tick);
void WriteDelay(int ticks);
FString Filename;
};
class OPLDumperMIDIDevice : public OPLMIDIDevice
{
public:

View file

@ -45,15 +45,13 @@
#include <math.h>
#include "doomtype.h"
#include "opl.h"
#include "m_random.h"
#include "xs_Float.h"
static FRandom pr_opl3;
#include "opl3_Float.h"
#define VOLUME_MUL 0.3333
static const double OPL_PI = 3.14159265358979323846; // matches value in gcc v2 math.h
namespace JavaOPL3
{
@ -1645,7 +1643,8 @@ double HighHatOperator::getOperatorOutput(OPL3 *OPL3, double modulator) {
// Top Cymbal, so we use the parent method and modify its output
// accordingly afterwards.
double operatorOutput = TopCymbalOperator::getOperatorOutput(OPL3, modulator, topCymbalOperatorPhase);
if(operatorOutput == 0) operatorOutput = pr_opl3.GenRand_Real1()*envelope;
double randval = rand() / (double)RAND_MAX;
if(operatorOutput == 0) operatorOutput = randval*envelope;
return operatorOutput;
}
@ -1667,7 +1666,8 @@ double SnareDrumOperator::getOperatorOutput(OPL3 *OPL3, double modulator) {
double operatorOutput = getOutput(modulator, phase, waveform);
double noise = pr_opl3.GenRand_Real1() * envelope;
double randval = rand() / (double)RAND_MAX;
double noise = randval * envelope;
if(operatorOutput/envelope != 1 && operatorOutput/envelope != -1) {
if(operatorOutput > 0) operatorOutput = noise;
@ -1777,7 +1777,7 @@ void OPL3DataStruct::loadTremoloTable()
void OperatorDataStruct::loadWaveforms() {
int i;
// 1st waveform: sinusoid.
double theta = 0, thetaIncrement = 2*M_PI / 1024;
double theta = 0, thetaIncrement = 2*OPL_PI / 1024;
for(i=0, theta=0; i<1024; i++, theta += thetaIncrement)
waveforms[0][i] = sin(theta);

View file

@ -24,12 +24,8 @@
* Ken Silverman's official web site: "http://www.advsys.net/ken"
*/
#include "doomtype.h"
#include "../opl.h"
#include <math.h>
#include "m_random.h"
static FRandom pr_opl;
typedef uintptr_t Bitu;
typedef intptr_t Bits;
@ -153,7 +149,7 @@ void operator_advance_drums(op_type* op_pt1, Bit32s vib1, op_type* op_pt2, Bit32
Bit32u c3 = op_pt3->tcount/FIXEDPT;
Bit32u phasebit = (((c1 & 0x88) ^ ((c1<<5) & 0x80)) | ((c3 ^ (c3<<2)) & 0x20)) ? 0x02 : 0x00;
Bit32u noisebit = pr_opl.GenRand32() & 1;
Bit32u noisebit = rand() & 1;
Bit32u snare_phase_bit = (Bit32u)(((Bitu)((op_pt1->tcount/FIXEDPT) / 0x100))&1);

View file

@ -1,4 +1,16 @@
#include "doomtype.h"
#include <stdint.h>
#if defined(__GNUC__)
// With versions of GCC newer than 4.2, it appears it was determined that the
// cost of an unaligned pointer on PPC was high enough to add padding to the
// end of packed structs. For whatever reason __packed__ and pragma pack are
// handled differently in this regard. Note that this only needs to be applied
// to types which are used in arrays or sizeof is needed. This also prevents
// code from taking references to the struct members.
#define FORCE_PACKED __attribute__((__packed__))
#else
#define FORCE_PACKED
#endif
#pragma pack(push, 1)
struct genmidi_op_t

View file

@ -29,8 +29,6 @@
#include <string.h>
#include "musicblock.h"
#include "c_cvars.h"
musicBlock::musicBlock ()
{
memset (this, 0, sizeof(*this));
@ -186,7 +184,7 @@ void musicBlock::voiceKeyOn(uint32_t slot, uint32_t channo, GenMidiInstrument *i
//
//----------------------------------------------------------------------------
CVAR(Bool, opl_singlevoice, 0, 0)
bool opl_singlevoice;
void musicBlock::noteOn(uint32_t channel, uint8_t key, int volume)
{

View file

@ -1,5 +1,5 @@
#pragma once
#include "doomtype.h"
#include <stdint.h>
#include "genmidi.h"
#include "oplio.h"

View file

@ -1,8 +1,6 @@
#ifndef OPL_H
#define OPL_H
#include "zstring.h"
// Abstract base class for OPL emulators
class OPLEmul

View file

@ -0,0 +1,238 @@
// ====================================================================================================================
// ====================================================================================================================
// xs_Float.h
//
// Source: "Know Your FPU: Fixing Floating Fast"
// http://www.stereopsis.com/sree/fpu2006.html
//
// xs_CRoundToInt: Round toward nearest, but ties round toward even (just like FISTP)
// xs_ToInt: Round toward zero, just like the C (int) cast
// xs_FloorToInt: Round down
// xs_CeilToInt: Round up
// xs_RoundToInt: Round toward nearest, but ties round up
// ====================================================================================================================
// ====================================================================================================================
#ifndef _xs_FLOAT_H_
#define _xs_FLOAT_H_
#include <stdint.h>
// ====================================================================================================================
// Defines
// ====================================================================================================================
#ifndef _xs_DEFAULT_CONVERSION
#define _xs_DEFAULT_CONVERSION 0
#endif //_xs_DEFAULT_CONVERSION
#if __BIG_ENDIAN__
#define _xs_iexp_ 0
#define _xs_iman_ 1
#else
#define _xs_iexp_ 1 //intel is little endian
#define _xs_iman_ 0
#endif //BigEndian_
#ifdef __GNUC__
#define finline inline
#else
#define finline __forceinline
#endif
typedef double real64;
union _xs_doubleints
{
real64 val;
uint32_t ival[2];
};
#if 0
#define _xs_doublecopysgn(a,b) ((int32_t*)&a)[_xs_iexp_]&=~(((int32_t*)&b)[_xs_iexp_]&0x80000000)
#define _xs_doubleisnegative(a) ((((int32_t*)&a)[_xs_iexp_])|0x80000000)
#endif
// ====================================================================================================================
// Constants
// ====================================================================================================================
const real64 _xs_doublemagic = real64 (6755399441055744.0); //2^52 * 1.5, uses limited precisicion to floor
const real64 _xs_doublemagicdelta = (1.5e-8); //almost .5f = .5f + 1e^(number of exp bit)
const real64 _xs_doublemagicroundeps = (.5f-_xs_doublemagicdelta); //almost .5f = .5f - 1e^(number of exp bit)
// ====================================================================================================================
// Prototypes
// ====================================================================================================================
static int32_t xs_CRoundToInt (real64 val, real64 dmr = _xs_doublemagic);
static int32_t xs_ToInt (real64 val, real64 dme = -_xs_doublemagicroundeps);
static int32_t xs_FloorToInt (real64 val, real64 dme = _xs_doublemagicroundeps);
static int32_t xs_CeilToInt (real64 val, real64 dme = _xs_doublemagicroundeps);
static int32_t xs_RoundToInt (real64 val);
//int32_t versions
finline static int32_t xs_CRoundToInt (int32_t val) {return val;}
finline static int32_t xs_ToInt (int32_t val) {return val;}
// ====================================================================================================================
// Fix Class
// ====================================================================================================================
template <int32_t N> class xs_Fix
{
public:
typedef int32_t Fix;
// ====================================================================================================================
// Basic Conversion from Numbers
// ====================================================================================================================
finline static Fix ToFix (int32_t val) {return val<<N;}
finline static Fix ToFix (real64 val) {return xs_ConvertToFixed(val);}
// ====================================================================================================================
// Basic Conversion to Numbers
// ====================================================================================================================
finline static real64 ToReal (Fix f) {return real64(f)/real64(1<<N);}
finline static int32_t ToInt (Fix f) {return f>>N;}
protected:
// ====================================================================================================================
// Helper function - mainly to preserve _xs_DEFAULT_CONVERSION
// ====================================================================================================================
finline static int32_t xs_ConvertToFixed (real64 val)
{
#if _xs_DEFAULT_CONVERSION==0
return xs_CRoundToInt(val, _xs_doublemagic/(1<<N));
#else
return (long)((val)*(1<<N));
#endif
}
};
finline static int32_t xs_ToFixed(int32_t n, real64 val)
{
#if _xs_DEFAULT_CONVERSION==0
return xs_CRoundToInt(val, _xs_doublemagic/(1<<n));
#else
return (long)((val)*(1<<N));
#endif
}
// ====================================================================================================================
// ====================================================================================================================
// Inline implementation
// ====================================================================================================================
// ====================================================================================================================
finline static int32_t xs_CRoundToInt(real64 val, real64 dmr)
{
#if _xs_DEFAULT_CONVERSION==0
_xs_doubleints uval;
uval.val = val + dmr;
return uval.ival[_xs_iman_];
#else
return int32_t(floor(val+.5));
#endif
}
// ====================================================================================================================
finline static int32_t xs_ToInt(real64 val, real64 dme)
{
/* unused - something else I tried...
_xs_doublecopysgn(dme,val);
return xs_CRoundToInt(val+dme);
return 0;
*/
#if _MSC_VER >= 1400
// VC++ 2005's standard cast is a little bit faster than this
// magic number code. (Which is pretty amazing!) SSE has the
// fastest C-style float->int conversion, but unfortunately,
// checking for SSE support every time you need to do a
// conversion completely negates its performance advantage.
return int32_t(val);
#else
#if _xs_DEFAULT_CONVERSION==0
return (val<0) ? xs_CRoundToInt(val-dme) :
xs_CRoundToInt(val+dme);
#else
return int32_t(val);
#endif
#endif
}
// ====================================================================================================================
finline static int32_t xs_FloorToInt(real64 val, real64 dme)
{
#if _xs_DEFAULT_CONVERSION==0
return xs_CRoundToInt (val - dme);
#else
return floor(val);
#endif
}
// ====================================================================================================================
finline static int32_t xs_CeilToInt(real64 val, real64 dme)
{
#if _xs_DEFAULT_CONVERSION==0
return xs_CRoundToInt (val + dme);
#else
return ceil(val);
#endif
}
// ====================================================================================================================
finline static int32_t xs_RoundToInt(real64 val)
{
#if _xs_DEFAULT_CONVERSION==0
// Yes, it is important that two fadds be generated, so you cannot override the dmr
// passed to xs_CRoundToInt with _xs_doublemagic + _xs_doublemagicdelta. If you do,
// you'll end up with Banker's Rounding again.
return xs_CRoundToInt (val + _xs_doublemagicdelta);
#else
return floor(val+.5);
#endif
}
// ====================================================================================================================
// ====================================================================================================================
// Unsigned variants
// ====================================================================================================================
// ====================================================================================================================
finline static uint32_t xs_CRoundToUInt(real64 val)
{
return (uint32_t)xs_CRoundToInt(val);
}
finline static uint32_t xs_FloorToUInt(real64 val)
{
return (uint32_t)xs_FloorToInt(val);
}
finline static uint32_t xs_CeilToUInt(real64 val)
{
return (uint32_t)xs_CeilToInt(val);
}
finline static uint32_t xs_RoundToUInt(real64 val)
{
return (uint32_t)xs_RoundToInt(val);
}
// ====================================================================================================================
// ====================================================================================================================
#endif // _xs_FLOAT_H_

View file

@ -43,6 +43,8 @@
#include "w_wad.h"
#include "templates.h"
#include "c_cvars.h"
#include "doomtype.h"
#include "i_musicinterns.h"
#define IMF_RATE 700.0

View file

@ -1,3 +1,4 @@
#pragma once
#include <mutex>
#include "musicblock.h"

View file

@ -24,13 +24,13 @@
//
#include <math.h>
#include <assert.h>
#include <algorithm>
#include "genmidi.h"
#include "oplio.h"
#include "opl.h"
#include "c_cvars.h"
#include "templates.h"
const double HALF_PI = (M_PI*0.5);
const double HALF_PI = (3.14159265358979323846 * 0.5);
OPLio::~OPLio()
{
@ -52,7 +52,7 @@ void OPLio::WriteDelay(int ticks)
int OPLio::Init(int core, uint32_t numchips, bool stereo, bool initopl3)
{
assert(numchips >= 1 && numchips <= countof(chips));
assert(numchips >= 1 && numchips <= OPL_NUM_VOICES);
uint32_t i;
IsOPL3 = (core == 1 || core == 2 || core == 3);
@ -113,12 +113,12 @@ void OPLio::WriteInitState(bool initopl3)
void OPLio::Reset(void)
{
for (size_t i = 0; i < countof(chips); ++i)
for (auto &c : chips)
{
if (chips[i] != NULL)
if (c != nullptr)
{
delete chips[i];
chips[i] = NULL;
delete c;
c = nullptr;
}
}
}
@ -347,7 +347,7 @@ void OPLio::WriteVolume(uint32_t channel, struct GenMidiVoice *voice, uint32_t v
{
if (voice != nullptr)
{
uint32_t full_volume = volumetable[MIN<uint32_t>(127, (uint32_t)((uint64_t)vol1*vol2*vol3) / (127 * 127))];
uint32_t full_volume = volumetable[std::min<uint32_t>(127, (uint32_t)((uint64_t)vol1*vol2*vol3) / (127 * 127))];
int reg_volume2 = ((0x3f - voice->carrier.level) * full_volume) / 128;
reg_volume2 = (0x3f - reg_volume2) | voice->carrier.scale;
WriteOperator(OPL_REGS_LEVEL, channel, 1, reg_volume2);

View file

@ -84,18 +84,6 @@ struct OPLio
bool IsOPL3;
};
struct DiskWriterIO : public OPLio
{
DiskWriterIO(const char *filename);
~DiskWriterIO();
int Init(uint32_t numchips, bool notused, bool initopl3);
void SetClockRate(double samples_per_tick);
void WriteDelay(int ticks);
FString Filename;
};
struct OPLChannel
{
uint32_t Instrument;