#ifndef FM_OPNA_H
#define FM_OPNA_H
#include "fmgen.h"
#include "fmtimer.h"
#include "psg.h"
namespace FM
{
class OPNBase : public Timer
{
public:
OPNBase();
bool Init(uint c, uint r);
virtual void Reset();
void SetVolumeFM(int db);
void SetVolumePSG(int db);
void SetLPFCutoff(uint freq) {}
protected:
void SetParameter(Channel4* ch, uint addr, uint data);
void SetPrescaler(uint p);
void RebuildTimeTable();
int fmvolume;
uint clock; uint rate; uint psgrate; uint status;
Channel4* csmch;
static uint32 lfotable[8];
private:
void TimerA();
uint8 prescale;
protected:
Chip chip;
PSG psg;
};
class OPNABase : public OPNBase
{
public:
OPNABase();
~OPNABase();
uint ReadStatus() { return status & 0x03; }
uint ReadStatusEx();
void SetChannelMask(uint mask);
private:
virtual void Intr(bool) {}
void MakeTable2();
protected:
bool Init(uint c, uint r, bool);
bool SetRate(uint c, uint r, bool);
void Reset();
void SetReg(uint addr, uint data);
void SetADPCMBReg(uint reg, uint data);
uint GetReg(uint addr);
protected:
void FMMix(Sample* buffer, int nsamples);
void Mix6(Sample* buffer, int nsamples, int activech);
void MixSubS(int activech, ISample**);
void MixSubSL(int activech, ISample**);
void SetStatus(uint bit);
void ResetStatus(uint bit);
void UpdateStatus();
void LFO();
void DecodeADPCMB();
void ADPCMBMix(Sample* dest, uint count);
void WriteRAM(uint data);
uint ReadRAM();
int ReadRAMN();
int DecodeADPCMBSample(uint);
uint8 pan[6];
uint8 fnum2[9];
uint8 reg22;
uint reg29;
uint stmask;
uint statusnext;
uint32 lfocount;
uint32 lfodcount;
uint fnum[6];
uint fnum3[3];
uint8* adpcmbuf; uint adpcmmask; uint adpcmnotice; uint startaddr; uint stopaddr; uint memaddr; uint limitaddr; int adpcmlevel; int adpcmvolume;
int adpcmvol;
uint deltan; int adplc; int adpld; uint adplbase; int adpcmx; int adpcmd; int adpcmout; int apout0; int apout1;
uint adpcmreadbuf; bool adpcmplay; int8 granuality;
bool adpcmmask_;
uint8 control1; uint8 control2; uint8 adpcmreg[8];
int rhythmmask_;
Channel4 ch[6];
uint8 ch6dac_enable;
uint8 ch6dac_disable;
static void BuildLFOTable();
static int amtable[FM_LFOENTS];
static int pmtable[FM_LFOENTS];
static int32 tltable[FM_TLENTS+FM_TLPOS];
static bool tablehasmade;
};
class OPN : public OPNBase
{
public:
OPN();
virtual ~OPN() {}
bool Init(uint c, uint r, bool=false, const char* =0);
bool SetRate(uint c, uint r, bool=false);
void Reset();
void Mix(Sample* buffer, int nsamples);
void SetReg(uint addr, uint data);
uint GetReg(uint addr);
uint ReadStatus() { return status & 0x03; }
uint ReadStatusEx() { return 0xff; }
void SetChannelMask(uint mask);
void SetPan(uint pan);
int dbgGetOpOut(int c, int s) { return ch[c].op[s].dbgopout_; }
int dbgGetPGOut(int c, int s) { return ch[c].op[s].dbgpgout_; }
Channel4* dbgGetCh(int c) { return &ch[c]; }
private:
virtual void Intr(bool) {}
void SetStatus(uint bit);
void ResetStatus(uint bit);
uint fnum[3];
uint fnum3[3];
uint8 fnum2[6];
Channel4 ch[3];
uint8 pan;
};
class OPNA : public OPNABase
{
public:
OPNA();
virtual ~OPNA();
bool Init(uint c, uint r, bool = false, const char* rhythmpath=0);
bool LoadRhythmSample(const char*);
bool SetRate(uint c, uint r, bool = false);
void Mix(Sample* buffer, int nsamples);
void Reset();
void SetReg(uint addr, uint data);
uint GetReg(uint addr);
void SetVolumeADPCM(int db);
void SetVolumeRhythmTotal(int db);
void SetVolumeRhythm(int index, int db);
uint8* GetADPCMBuffer() { return adpcmbuf; }
int dbgGetOpOut(int c, int s) { return ch[c].op[s].dbgopout_; }
int dbgGetPGOut(int c, int s) { return ch[c].op[s].dbgpgout_; }
Channel4* dbgGetCh(int c) { return &ch[c]; }
private:
struct Rhythm
{
uint8 pan; int8 level; int volume; int16* sample; uint size; uint pos; uint step; uint rate; };
void RhythmMix(Sample* buffer, uint count);
Rhythm rhythm[6];
int8 rhythmtl; int rhythmtvol;
uint8 rhythmkey; };
class OPNB : public OPNABase
{
public:
OPNB();
virtual ~OPNB();
bool Init(uint c, uint r, bool = false,
uint8 *_adpcma = 0, int _adpcma_size = 0,
uint8 *_adpcmb = 0, int _adpcmb_size = 0);
bool SetRate(uint c, uint r, bool = false);
void Mix(Sample* buffer, int nsamples);
void Reset();
void SetReg(uint addr, uint data);
uint GetReg(uint addr);
uint ReadStatusEx();
void SetVolumeADPCMATotal(int db);
void SetVolumeADPCMA(int index, int db);
void SetVolumeADPCMB(int db);
private:
struct ADPCMA
{
uint8 pan; int8 level; int volume; uint pos; uint step;
uint start; uint stop; uint nibble; int adpcmx; int adpcmd; };
int DecodeADPCMASample(uint);
void ADPCMAMix(Sample* buffer, uint count);
static void InitADPCMATable();
uint8* adpcmabuf; int adpcmasize;
ADPCMA adpcma[6];
int8 adpcmatl; int adpcmatvol;
uint8 adpcmakey; int adpcmastep;
uint8 adpcmareg[32];
static int jedi_table[(48+1)*16];
Channel4 ch[6];
};
class OPN2 : public OPNABase
{
public:
OPN2();
virtual ~OPN2();
bool Init(uint c, uint r, bool=false, const char* =0);
bool SetRate(uint c, uint r, bool);
void Reset();
void Mix(Sample* buffer, int nsamples);
void SetReg(uint addr, uint data);
uint GetReg(uint addr);
uint ReadStatus() { return status & 0x03; }
uint ReadStatusEx() { return 0xff; }
void SetChannelMask(uint mask);
void SetVolumePCM(int db);
void PCMMix(Sample* dest, uint count);
private:
virtual void Intr(bool) {}
Channel4 ch[6];
uint8 *ch6dac_fifo;
uint32 ch6dac_ptr;
uint32 ch6dac_vol;
uint8 ch6dac_pan;
uint8 ch6dac_data;
bool ch6dac_interpolation;
};
}
inline void FM::OPNBase::RebuildTimeTable()
{
int p = prescale;
prescale = -1;
SetPrescaler(p);
}
inline void FM::OPNBase::SetVolumePSG(int db)
{
psg.SetVolume(db);
}
#endif