gzdoom-gles/libraries/opnmidi/chips/np2/fmgen_fmgen.h
Wohlstand 87d46ddd11 Update libOPNMIDI library to 1.5.0
## 1.5.0   2020-09-28
 * Drum note length expanding is now supported in real-time mode (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!)
 * Added support for OPNA chip with Neko Project II Kai YM2602 emulator usage (Thanks to [Jean Pierre Cimalando](https://github.com/jpcima) for a work!)
 * Added VGM file dumper which allows to output OPN2 commands into VGM file. (A new MIDI to VGM tool is now created with basing on libOPNMIDI)
 * Fixed an incorrect work of CC-121 (See https://github.com/Wohlstand/libADLMIDI/issues/227 for details)
 * Internality has been refactored and improved
2020-10-04 12:50:10 +02:00

342 lines
7.7 KiB
C++

// ---------------------------------------------------------------------------
// FM Sound Generator
// Copyright (C) cisc 1998, 2001.
// ---------------------------------------------------------------------------
// $Id: fmgen.h,v 1.37 2003/08/25 13:33:11 cisc Exp $
#ifndef FM_GEN_H
#define FM_GEN_H
#include "fmgen_types.h"
// ---------------------------------------------------------------------------
// 出力サンプルの型
//
// libOPNMIDI: change int32 to int16
#define FM_SAMPLETYPE int16 // int16 or int32
// ---------------------------------------------------------------------------
// 定数その1
// 静的テーブルのサイズ
#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)
// サイン波の精度は 2^(1/256)
#define FM_CLENTS (0x1000 * 2) // sin + TL + LFO
// ---------------------------------------------------------------------------
namespace FM
{
// Types ----------------------------------------------------------------
typedef FM_SAMPLETYPE Sample;
typedef int32 ISample;
enum OpType { typeN=0, typeM=1 };
enum EGPhase { next, attack, decay, sustain, release, off };
void StoreSample(ISample& dest, int data);
class Chip;
struct ChipData;
// Operator -------------------------------------------------------------
struct OperatorData {
ISample out_;
ISample out2_;
ISample in2_;
uint dp_;
uint detune_;
uint detune2_;
uint multiple_;
uint32 pg_count_;
uint32 pg_diff_;
int32 pg_diff_lfo_;
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_;
#if 0 // libOPNMIDI: experimental SSG-EG
int ssg_offset_;
int ssg_vector_;
int ssg_phase_;
#endif
uint key_scale_rate_;
EGPhase eg_phase_;
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_;
bool inverted_;
bool held_;
};
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);
// static void SetAML(uint l);
// static void SetPML(uint l);
int Out() { return out_; }
int dbgGetIn2() { return in2_; }
void dbgStopPG() { pg_diff_ = 0; pg_diff_lfo_ = 0; }
void DataSave(struct OperatorData* data);
void DataLoad(struct OperatorData* data);
private:
typedef uint32 Counter;
Chip* chip_;
ISample out_, out2_;
ISample in2_;
// Phase Generator ------------------------------------------------------
uint32 PGCalc();
uint32 PGCalcL();
uint dp_; // ΔP
uint detune_; // Detune
uint detune2_; // DT2
uint multiple_; // Multiple
uint32 pg_count_; // Phase 現在値
uint32 pg_diff_; // Phase 差分値
int32 pg_diff_lfo_; // Phase 差分値 >> x
// Envelop Generator ---------------------------------------------------
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_; // OP の種類 (M, N...)
uint bn_; // Block/Note
int eg_level_; // EG の出力値
int eg_level_on_next_phase_; // 次の eg_phase_ に移る値
int eg_count_; // EG の次の変移までの時間
int eg_count_diff_; // eg_count_ の差分
int eg_out_; // EG+TL を合わせた出力値
int tl_out_; // TL 分の出力値
// int pm_depth_; // PM depth
// int am_depth_; // AM depth
int eg_rate_;
int eg_curve_count_;
#if 0 // libOPNMIDI: experimental SSG-EG
int ssg_offset_;
int ssg_vector_;
int ssg_phase_;
#endif
uint key_scale_rate_; // key scale rate
EGPhase eg_phase_;
uint* ams_;
uint ms_;
uint tl_; // Total Level (0-127)
uint tl_latch_; // Total Level Latch (for CSM mode)
uint ar_; // Attack Rate (0-63)
uint dr_; // Decay Rate (0-63)
uint sr_; // Sustain Rate (0-63)
uint sl_; // Sustain Level (0-127)
uint rr_; // Release Rate (0-63)
uint ks_; // Keyscale (0-3)
uint ssg_type_; // SSG-Type Envelop Control
bool keyon_;
bool amon_; // enable Amplitude Modulation
bool param_changed_; // パラメータが更新された
bool mute_;
bool inverted_;
bool held_;
// Tables ---------------------------------------------------------------
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();
// friends --------------------------------------------------------------
friend class Channel4;
public:
int dbgopout_;
int dbgpgout_;
static const int32* dbgGetClTable() { return cltable; }
static const uint* dbgGetSineTable() { return sinetable; }
};
// 4-op Channel ---------------------------------------------------------
struct Channel4Data {
uint fb;
int buf[4];
int algo_;
struct OperatorData op[4];
};
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(); }
void DataSave(struct Channel4Data* data);
void DataLoad(struct Channel4Data* data);
private:
static const uint8 fbtable[8];
uint fb;
int buf[4];
int* in[3]; // 各 OP の入力ポインタ
int* out[3]; // 各 OP の出力ポインタ
int* pms;
int algo_;
Chip* chip_;
static void MakeTable();
static bool tablehasmade;
static int kftable[64];
public:
Operator op[4];
};
// Chip resource
struct ChipData {
uint ratio_;
uint aml_;
uint pml_;
int pmv_;
OpType optype_;
uint32 multable_[4][16];
};
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_; }
void DataSave(struct ChipData* data);
void DataLoad(struct ChipData* data);
private:
void MakeTable();
uint ratio_;
uint aml_;
uint pml_;
int pmv_;
// OpType optype_;
uint32 multable_[4][16];
};
}
#endif // FM_GEN_H