|
@@ -0,0 +1,290 @@
|
|
|
+/*
|
|
|
+ * Copyright (C) 2002-2015 The DOSBox Team
|
|
|
+ *
|
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
|
+ * (at your option) any later version.
|
|
|
+ *
|
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
+ * GNU General Public License for more details.
|
|
|
+ *
|
|
|
+ * You should have received a copy of the GNU General Public License
|
|
|
+ * along with this program; if not, write to the Free Software
|
|
|
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
+ */
|
|
|
+
|
|
|
+//#include "adlib.h"
|
|
|
+//#include "dosbox.h"
|
|
|
+
|
|
|
+/*
|
|
|
+define Bits, Bitu, Bit32s, Bit32u, Bit16s, Bit16u, Bit8s, Bit8u here
|
|
|
+*/
|
|
|
+
|
|
|
+#if defined(_MSC_VER) && _MSC_VER <= 1600
|
|
|
+#include <windows.h>
|
|
|
+#define uintptr_t ULONG_PTR
|
|
|
+#define intptr_t LONG_PTR
|
|
|
+#define uint32_t DWORD
|
|
|
+#define int32_t INT
|
|
|
+#define uint16_t WORD
|
|
|
+#define int16_t SHORT
|
|
|
+#define uint8_t BYTE
|
|
|
+#define int8_t CHAR
|
|
|
+#else
|
|
|
+#include <stdint.h>
|
|
|
+#endif
|
|
|
+
|
|
|
+typedef uintptr_t Bitu;
|
|
|
+typedef intptr_t Bits;
|
|
|
+typedef uint32_t Bit32u;
|
|
|
+typedef int32_t Bit32s;
|
|
|
+typedef uint16_t Bit16u;
|
|
|
+typedef int16_t Bit16s;
|
|
|
+typedef uint8_t Bit8u;
|
|
|
+typedef int8_t Bit8s;
|
|
|
+
|
|
|
+/*
|
|
|
+define attribution that inlines/forces inlining of a function (optional)
|
|
|
+*/
|
|
|
+#define OPL_INLINE inline
|
|
|
+
|
|
|
+#define GCC_UNLIKELY(x) (x)
|
|
|
+
|
|
|
+//Use 8 handlers based on a small logatirmic wavetabe and an exponential table for volume
|
|
|
+#define WAVE_HANDLER 10
|
|
|
+//Use a logarithmic wavetable with an exponential table for volume
|
|
|
+#define WAVE_TABLELOG 11
|
|
|
+//Use a linear wavetable with a multiply table for volume
|
|
|
+#define WAVE_TABLEMUL 12
|
|
|
+
|
|
|
+//Select the type of wave generator routine
|
|
|
+#define DBOPL_WAVE WAVE_TABLEMUL
|
|
|
+
|
|
|
+namespace DBOPL {
|
|
|
+
|
|
|
+ struct Chip;
|
|
|
+ struct Operator;
|
|
|
+ struct Channel;
|
|
|
+
|
|
|
+#if (DBOPL_WAVE == WAVE_HANDLER)
|
|
|
+ typedef Bits(DB_FASTCALL *WaveHandler) (Bitu i, Bitu volume);
|
|
|
+#endif
|
|
|
+
|
|
|
+ typedef Bits(DBOPL::Operator::*VolumeHandler) ();
|
|
|
+ typedef Channel* (DBOPL::Channel::*SynthHandler) (Chip* chip, Bit32u samples, Bit32s* output);
|
|
|
+
|
|
|
+ //Different synth modes that can generate blocks of data
|
|
|
+ typedef enum {
|
|
|
+ sm2AM,
|
|
|
+ sm2FM,
|
|
|
+ sm3AM,
|
|
|
+ sm3FM,
|
|
|
+ sm4Start,
|
|
|
+ sm3FMFM,
|
|
|
+ sm3AMFM,
|
|
|
+ sm3FMAM,
|
|
|
+ sm3AMAM,
|
|
|
+ sm6Start,
|
|
|
+ sm2Percussion,
|
|
|
+ sm3Percussion,
|
|
|
+ } SynthMode;
|
|
|
+
|
|
|
+ //Shifts for the values contained in chandata variable
|
|
|
+ enum {
|
|
|
+ SHIFT_KSLBASE = 16,
|
|
|
+ SHIFT_KEYCODE = 24,
|
|
|
+ };
|
|
|
+
|
|
|
+ struct Operator {
|
|
|
+ public:
|
|
|
+ //Masks for operator 20 values
|
|
|
+ enum {
|
|
|
+ MASK_KSR = 0x10,
|
|
|
+ MASK_SUSTAIN = 0x20,
|
|
|
+ MASK_VIBRATO = 0x40,
|
|
|
+ MASK_TREMOLO = 0x80,
|
|
|
+ };
|
|
|
+
|
|
|
+ typedef enum {
|
|
|
+ OFF,
|
|
|
+ RELEASE,
|
|
|
+ SUSTAIN,
|
|
|
+ DECAY,
|
|
|
+ ATTACK,
|
|
|
+ } State;
|
|
|
+
|
|
|
+ VolumeHandler volHandler;
|
|
|
+
|
|
|
+#if (DBOPL_WAVE == WAVE_HANDLER)
|
|
|
+ WaveHandler waveHandler; //Routine that generate a wave
|
|
|
+#else
|
|
|
+ Bit16s* waveBase;
|
|
|
+ Bit32u waveMask;
|
|
|
+ Bit32u waveStart;
|
|
|
+#endif
|
|
|
+ Bit32u waveIndex; //WAVE_BITS shifted counter of the frequency index
|
|
|
+ Bit32u waveAdd; //The base frequency without vibrato
|
|
|
+ Bit32u waveCurrent; //waveAdd + vibratao
|
|
|
+
|
|
|
+ Bit32u chanData; //Frequency/octave and derived data coming from whatever channel controls this
|
|
|
+ Bit32u freqMul; //Scale channel frequency with this, TODO maybe remove?
|
|
|
+ Bit32u vibrato; //Scaled up vibrato strength
|
|
|
+ Bit32s sustainLevel; //When stopping at sustain level stop here
|
|
|
+ Bit32s totalLevel; //totalLevel is added to every generated volume
|
|
|
+ Bit32u currentLevel; //totalLevel + tremolo
|
|
|
+ Bit32s volume; //The currently active volume
|
|
|
+
|
|
|
+ Bit32u attackAdd; //Timers for the different states of the envelope
|
|
|
+ Bit32u decayAdd;
|
|
|
+ Bit32u releaseAdd;
|
|
|
+ Bit32u rateIndex; //Current position of the evenlope
|
|
|
+
|
|
|
+ Bit8u rateZero; //Bits for the different states of the envelope having no changes
|
|
|
+ Bit8u keyOn; //Bitmask of different values that can generate keyon
|
|
|
+ //Registers, also used to check for changes
|
|
|
+ Bit8u reg20, reg40, reg60, reg80, regE0;
|
|
|
+ //Active part of the envelope we're in
|
|
|
+ Bit8u state;
|
|
|
+ //0xff when tremolo is enabled
|
|
|
+ Bit8u tremoloMask;
|
|
|
+ //Strength of the vibrato
|
|
|
+ Bit8u vibStrength;
|
|
|
+ //Keep track of the calculated KSR so we can check for changes
|
|
|
+ Bit8u ksr;
|
|
|
+ private:
|
|
|
+ void SetState(Bit8u s);
|
|
|
+ void UpdateAttack(const Chip* chip);
|
|
|
+ void UpdateRelease(const Chip* chip);
|
|
|
+ void UpdateDecay(const Chip* chip);
|
|
|
+ public:
|
|
|
+ void UpdateAttenuation();
|
|
|
+ void UpdateRates(const Chip* chip);
|
|
|
+ void UpdateFrequency();
|
|
|
+
|
|
|
+ void Write20(const Chip* chip, Bit8u val);
|
|
|
+ void Write40(const Chip* chip, Bit8u val);
|
|
|
+ void Write60(const Chip* chip, Bit8u val);
|
|
|
+ void Write80(const Chip* chip, Bit8u val);
|
|
|
+ void WriteE0(const Chip* chip, Bit8u val);
|
|
|
+
|
|
|
+ bool Silent() const;
|
|
|
+ void Prepare(const Chip* chip);
|
|
|
+
|
|
|
+ void KeyOn(Bit8u mask);
|
|
|
+ void KeyOff(Bit8u mask);
|
|
|
+
|
|
|
+ template< State state>
|
|
|
+ Bits TemplateVolume();
|
|
|
+
|
|
|
+ Bit32s RateForward(Bit32u add);
|
|
|
+ Bitu ForwardWave();
|
|
|
+ Bitu ForwardVolume();
|
|
|
+
|
|
|
+ Bits GetSample(Bits modulation);
|
|
|
+ Bits GetWave(Bitu index, Bitu vol);
|
|
|
+ public:
|
|
|
+ Operator();
|
|
|
+ };
|
|
|
+
|
|
|
+ struct Channel {
|
|
|
+ Operator op[2];
|
|
|
+ inline Operator* Op(Bitu index) {
|
|
|
+ return &((this + (index >> 1))->op[index & 1]);
|
|
|
+ }
|
|
|
+ SynthHandler synthHandler;
|
|
|
+ Bit32u chanData; //Frequency/octave and derived values
|
|
|
+ Bit32s old[2]; //Old data for feedback
|
|
|
+
|
|
|
+ Bit8u feedback; //Feedback shift
|
|
|
+ Bit8u regB0; //Register values to check for changes
|
|
|
+ Bit8u regC0;
|
|
|
+ //This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel
|
|
|
+ Bit8u fourMask;
|
|
|
+ Bit8s maskLeft; //Sign extended values for both channel's panning
|
|
|
+ Bit8s maskRight;
|
|
|
+
|
|
|
+ //Forward the channel data to the operators of the channel
|
|
|
+ void SetChanData(const Chip* chip, Bit32u data);
|
|
|
+ //Change in the chandata, check for new values and if we have to forward to operators
|
|
|
+ void UpdateFrequency(const Chip* chip, Bit8u fourOp);
|
|
|
+ void WriteA0(const Chip* chip, Bit8u val);
|
|
|
+ void WriteB0(const Chip* chip, Bit8u val);
|
|
|
+ void WriteC0(const Chip* chip, Bit8u val);
|
|
|
+ void ResetC0(const Chip* chip);
|
|
|
+
|
|
|
+ //call this for the first channel
|
|
|
+ template< bool opl3Mode >
|
|
|
+ void GeneratePercussion(Chip* chip, Bit32s* output);
|
|
|
+
|
|
|
+ //Generate blocks of data in specific modes
|
|
|
+ template<SynthMode mode>
|
|
|
+ Channel* BlockTemplate(Chip* chip, Bit32u samples, Bit32s* output);
|
|
|
+ Channel();
|
|
|
+ };
|
|
|
+
|
|
|
+ struct Chip {
|
|
|
+ //This is used as the base counter for vibrato and tremolo
|
|
|
+ Bit32u lfoCounter;
|
|
|
+ Bit32u lfoAdd;
|
|
|
+
|
|
|
+
|
|
|
+ Bit32u noiseCounter;
|
|
|
+ Bit32u noiseAdd;
|
|
|
+ Bit32u noiseValue;
|
|
|
+
|
|
|
+ //Frequency scales for the different multiplications
|
|
|
+ Bit32u freqMul[16];
|
|
|
+ //Rates for decay and release for rate of this chip
|
|
|
+ Bit32u linearRates[76];
|
|
|
+ //Best match attack rates for the rate of this chip
|
|
|
+ Bit32u attackRates[76];
|
|
|
+
|
|
|
+ //18 channels with 2 operators each
|
|
|
+ Channel chan[18];
|
|
|
+
|
|
|
+ Bit8u reg104;
|
|
|
+ Bit8u reg08;
|
|
|
+ Bit8u reg04;
|
|
|
+ Bit8u regBD;
|
|
|
+ Bit8u vibratoIndex;
|
|
|
+ Bit8u tremoloIndex;
|
|
|
+ Bit8s vibratoSign;
|
|
|
+ Bit8u vibratoShift;
|
|
|
+ Bit8u tremoloValue;
|
|
|
+ Bit8u vibratoStrength;
|
|
|
+ Bit8u tremoloStrength;
|
|
|
+ //Mask for allowed wave forms
|
|
|
+ Bit8u waveFormMask;
|
|
|
+ //0 or -1 when enabled
|
|
|
+ Bit8s opl3Active;
|
|
|
+
|
|
|
+ //Return the maximum amount of samples before and LFO change
|
|
|
+ Bit32u ForwardLFO(Bit32u samples);
|
|
|
+ Bit32u ForwardNoise();
|
|
|
+
|
|
|
+ void WriteBD(Bit8u val);
|
|
|
+ void WriteReg(Bit32u reg, Bit8u val);
|
|
|
+
|
|
|
+ Bit32u WriteAddr(Bit32u port, Bit8u val);
|
|
|
+
|
|
|
+ void GenerateBlock2(Bitu samples, Bit32s* output);
|
|
|
+ void GenerateBlock3(Bitu samples, Bit32s* output);
|
|
|
+
|
|
|
+ //void Generate( Bit32u samples );
|
|
|
+ void Setup(Bit32u r);
|
|
|
+
|
|
|
+ Chip();
|
|
|
+ };
|
|
|
+
|
|
|
+ struct Handler {
|
|
|
+ DBOPL::Chip chip;
|
|
|
+ Bit32s buffer[512 * 2];
|
|
|
+ Bit32u WriteAddr(Bit32u port, Bit8u val);
|
|
|
+ void WriteReg(Bit32u addr, Bit8u val);
|
|
|
+ void Generate(Bit16s* buf, Bitu samples);
|
|
|
+ void Init(Bitu rate);
|
|
|
+ };
|
|
|
+}; //Namespace
|