diff options
Diffstat (limited to 'src/chips/dosbox/dbopl.h')
-rw-r--r-- | src/chips/dosbox/dbopl.h | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/src/chips/dosbox/dbopl.h b/src/chips/dosbox/dbopl.h new file mode 100644 index 0000000..b5b2ba1 --- /dev/null +++ b/src/chips/dosbox/dbopl.h @@ -0,0 +1,314 @@ +/* + * Copyright (C) 2002-2010 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. + */ + + +/* BEGIN MIDIPLAY GLUE */ +#include <stdint.h> +#include <stdlib.h> +typedef unsigned long Bitu; +typedef signed long Bits; +typedef unsigned Bit32u; +typedef int Bit32s; +typedef unsigned short Bit16u; +typedef signed short Bit16s; +typedef unsigned char Bit8u; +typedef signed char Bit8s; +#define INLINE inline +#ifdef _MSC_VER +#define GCC_UNLIKELY(x) (!!(x) == 0) +#define GCC_LIKELY(x) (!!(x) == 1) +#else +#define GCC_UNLIKELY(x) __builtin_expect((x),0) +#define GCC_LIKELY(x) __builtin_expect((x),1) +#endif +/* END MIDIPLAY GLUE */ + +//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 + +#ifdef _WIN32 +# ifdef _MSC_VER +# ifdef _WIN64 +typedef __int64 ssize_t; +# else +typedef __int32 ssize_t; +# endif +# else +# ifdef _WIN64 +typedef int64_t ssize_t; +# else +typedef int32_t ssize_t; +# endif +# endif +#endif + +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(); + char ____padding[5]; + }; + + 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(); + char ____padding[6]; + }; + + 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 GenerateBlock2_Mix(Bitu samples, Bit32s *output); + void GenerateBlock3_Mix(Bitu samples, Bit32s *output); + + void Generate(Bit32u samples); + void Setup(Bit32u r); + + Chip(); + }; + + struct Handler + { + DBOPL::Chip chip; + Bit32u WriteAddr(Bit32u port, Bit8u val); + void WriteReg(Bit32u addr, Bit8u val); + void Generate(void(*AddSamples_m32)(Bitu, Bit32s *), + void(*AddSamples_s32)(Bitu, Bit32s *), + Bitu samples); + void GenerateArr(Bit32s *out, Bitu *samples); + void GenerateArr(Bit32s *out, ssize_t *samples); + void GenerateArr(Bit16s *out, ssize_t *samples); + void GenerateArrMix(Bit32s *out, ssize_t *samples); + void GenerateArrMix(Bit16s *out, ssize_t *samples); + void Init(Bitu rate); + }; + + +} //Namespace |