diff --git a/src/sound/music/i_musicinterns.h b/src/sound/music/i_musicinterns.h index dd0b8df19..81aaa4203 100644 --- a/src/sound/music/i_musicinterns.h +++ b/src/sound/music/i_musicinterns.h @@ -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: diff --git a/src/sound/oplsynth/OPL3.cpp b/src/sound/oplsynth/OPL3.cpp index 291c24542..4aa69ce76 100644 --- a/src/sound/oplsynth/OPL3.cpp +++ b/src/sound/oplsynth/OPL3.cpp @@ -45,15 +45,13 @@ #include -#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); diff --git a/src/sound/oplsynth/dosbox/opl.cpp b/src/sound/oplsynth/dosbox/opl.cpp index 4209fa2fe..79d897198 100644 --- a/src/sound/oplsynth/dosbox/opl.cpp +++ b/src/sound/oplsynth/dosbox/opl.cpp @@ -24,12 +24,8 @@ * Ken Silverman's official web site: "http://www.advsys.net/ken" */ -#include "doomtype.h" #include "../opl.h" #include -#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); diff --git a/src/sound/oplsynth/genmidi.h b/src/sound/oplsynth/genmidi.h index f315f8245..82fbe3e51 100644 --- a/src/sound/oplsynth/genmidi.h +++ b/src/sound/oplsynth/genmidi.h @@ -1,4 +1,16 @@ -#include "doomtype.h" +#include + +#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 diff --git a/src/sound/oplsynth/musicblock.cpp b/src/sound/oplsynth/musicblock.cpp index 66c6b15a6..4d0aeb249 100644 --- a/src/sound/oplsynth/musicblock.cpp +++ b/src/sound/oplsynth/musicblock.cpp @@ -29,8 +29,6 @@ #include #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) { diff --git a/src/sound/oplsynth/musicblock.h b/src/sound/oplsynth/musicblock.h index f6cf2150c..cc2612b8b 100644 --- a/src/sound/oplsynth/musicblock.h +++ b/src/sound/oplsynth/musicblock.h @@ -1,5 +1,5 @@ #pragma once -#include "doomtype.h" +#include #include "genmidi.h" #include "oplio.h" diff --git a/src/sound/oplsynth/opl.h b/src/sound/oplsynth/opl.h index d5faa136c..57c394f26 100644 --- a/src/sound/oplsynth/opl.h +++ b/src/sound/oplsynth/opl.h @@ -1,8 +1,6 @@ #ifndef OPL_H #define OPL_H -#include "zstring.h" - // Abstract base class for OPL emulators class OPLEmul diff --git a/src/sound/oplsynth/opl3_Float.h b/src/sound/oplsynth/opl3_Float.h new file mode 100644 index 000000000..6c676ee3a --- /dev/null +++ b/src/sound/oplsynth/opl3_Float.h @@ -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 + +// ==================================================================================================================== +// 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 class xs_Fix +{ +public: + typedef int32_t Fix; + + // ==================================================================================================================== + // Basic Conversion from Numbers + // ==================================================================================================================== + finline static Fix ToFix (int32_t val) {return val<>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<= 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_ \ No newline at end of file diff --git a/src/sound/oplsynth/opl_mus_player.cpp b/src/sound/oplsynth/opl_mus_player.cpp index 3d68420e2..218bd9ada 100644 --- a/src/sound/oplsynth/opl_mus_player.cpp +++ b/src/sound/oplsynth/opl_mus_player.cpp @@ -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 diff --git a/src/sound/oplsynth/opl_mus_player.h b/src/sound/oplsynth/opl_mus_player.h index cecbd72fd..8fb89e1f7 100644 --- a/src/sound/oplsynth/opl_mus_player.h +++ b/src/sound/oplsynth/opl_mus_player.h @@ -1,3 +1,4 @@ +#pragma once #include #include "musicblock.h" diff --git a/src/sound/oplsynth/oplio.cpp b/src/sound/oplsynth/oplio.cpp index d28b8f242..1a7c93a43 100644 --- a/src/sound/oplsynth/oplio.cpp +++ b/src/sound/oplsynth/oplio.cpp @@ -24,13 +24,13 @@ // #include +#include +#include #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(127, (uint32_t)((uint64_t)vol1*vol2*vol3) / (127 * 127))]; + uint32_t full_volume = volumetable[std::min(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); diff --git a/src/sound/oplsynth/oplio.h b/src/sound/oplsynth/oplio.h index c46fd5157..604c6422f 100644 --- a/src/sound/oplsynth/oplio.h +++ b/src/sound/oplsynth/oplio.h @@ -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;