#ifndef FM_GEN_H
#define FM_GEN_H
#include "types.h"
#define FM_SAMPLETYPE int32
#define FM_LFOBITS 8
#define FM_TLBITS 7
#define FM_TLENTS (1 << FM_TLBITS)
#define FM_LFOENTS (1 << FM_LFOBITS)
#define FM_TLPOS (FM_TLENTS/4)
#define FM_CLENTS (0x1000 * 2)
namespace FM
{
typedef FM_SAMPLETYPE Sample;
typedef int32 ISample;
enum OpType { typeN=0, typeM=1 };
void StoreSample(ISample& dest, int data);
class Chip;
class Operator
{
public:
Operator();
void SetChip(Chip* chip) { chip_ = chip; }
static void MakeTimeTable(uint ratio);
ISample Calc(ISample in);
ISample CalcL(ISample in);
ISample CalcFB(uint fb);
ISample CalcFBL(uint fb);
ISample CalcN(uint noise);
void Prepare();
void KeyOn();
void KeyOff();
void Reset();
void ResetFB();
int IsOn();
void SetDT(uint dt);
void SetDT2(uint dt2);
void SetMULTI(uint multi);
void SetTL(uint tl, bool csm);
void SetKS(uint ks);
void SetAR(uint ar);
void SetDR(uint dr);
void SetSR(uint sr);
void SetRR(uint rr);
void SetSL(uint sl);
void SetSSGEC(uint ssgec);
void SetFNum(uint fnum);
void SetDPBN(uint dp, uint bn);
void SetMode(bool modulator);
void SetAMON(bool on);
void SetMS(uint ms);
void Mute(bool);
int Out() { return out_; }
int dbgGetIn2() { return in2_; }
void dbgStopPG() { pg_diff_ = 0; pg_diff_lfo_ = 0; }
private:
typedef uint32 Counter;
Chip* chip_;
ISample out_, out2_;
ISample in2_;
uint32 PGCalc();
uint32 PGCalcL();
uint dp_; uint detune_; uint detune2_; uint multiple_; uint32 pg_count_; uint32 pg_diff_; int32 pg_diff_lfo_;
enum EGPhase { next, attack, decay, sustain, release, off };
void EGCalc();
void EGStep();
void ShiftPhase(EGPhase nextphase);
void SSGShiftPhase(int mode);
void SetEGRate(uint);
void EGUpdate();
int FBCalc(int fb);
ISample LogToLin(uint a);
OpType type_; uint bn_; int eg_level_; int eg_level_on_next_phase_; int eg_count_; int eg_count_diff_; int eg_out_; int tl_out_; int eg_rate_;
int eg_curve_count_;
int ssg_offset_;
int ssg_vector_;
int ssg_phase_;
uint key_scale_rate_; EGPhase eg_phase_;
uint* ams_;
uint ms_;
uint tl_; uint tl_latch_; uint ar_; uint dr_; uint sr_; uint sl_; uint rr_; uint ks_; uint ssg_type_;
bool keyon_;
bool amon_; bool param_changed_; bool mute_;
static Counter rate_table[16];
static uint32 multable[4][16];
static const uint8 notetable[128];
static const int8 dttable[256];
static const int8 decaytable1[64][8];
static const int decaytable2[16];
static const int8 attacktable[64][8];
static const int ssgenvtable[8][2][3][2];
static uint sinetable[1024];
static int32 cltable[FM_CLENTS];
static bool tablehasmade;
static void MakeTable();
friend class Channel4;
friend void FM_NextPhase(Operator* op);
public:
int dbgopout_;
int dbgpgout_;
static const int32* dbgGetClTable() { return cltable; }
static const uint* dbgGetSineTable() { return sinetable; }
};
class Channel4
{
public:
Channel4();
void SetChip(Chip* chip);
void SetType(OpType type);
ISample Calc();
ISample CalcL();
ISample CalcN(uint noise);
ISample CalcLN(uint noise);
void SetFNum(uint fnum);
void SetFB(uint fb);
void SetKCKF(uint kc, uint kf);
void SetAlgorithm(uint algo);
int Prepare();
void KeyControl(uint key);
void Reset();
void SetMS(uint ms);
void Mute(bool);
void Refresh();
void dbgStopPG() { for (int i=0; i<4; i++) op[i].dbgStopPG(); }
private:
static const uint8 fbtable[8];
uint fb;
int buf[4];
int* in[3]; int* out[3]; int* pms;
int algo_;
Chip* chip_;
static void MakeTable();
static bool tablehasmade;
static int kftable[64];
public:
Operator op[4];
};
class Chip
{
public:
Chip();
void SetRatio(uint ratio);
void SetAML(uint l);
void SetPML(uint l);
void SetPMV(int pmv) { pmv_ = pmv; }
uint32 GetMulValue(uint dt2, uint mul) { return multable_[dt2][mul]; }
uint GetAML() { return aml_; }
uint GetPML() { return pml_; }
int GetPMV() { return pmv_; }
uint GetRatio() { return ratio_; }
private:
void MakeTable();
uint ratio_;
uint aml_;
uint pml_;
int pmv_;
OpType optype_;
uint32 multable_[4][16];
};
}
#endif