mirror of
https://github.com/ZDoom/ZMusic.git
synced 2024-12-04 09:32:23 +00:00
275 lines
4.8 KiB
C
275 lines
4.8 KiB
C
|
// ---------------------------------------------------------------------------
|
||
|
// FM Sound Generator
|
||
|
// Copyright (C) cisc 1998, 2003.
|
||
|
// ---------------------------------------------------------------------------
|
||
|
// $Id: fmgeninl.h,v 1.26 2003/06/12 13:14:36 cisc Exp $
|
||
|
|
||
|
#ifndef FM_GEN_INL_H
|
||
|
#define FM_GEN_INL_H
|
||
|
|
||
|
// ---------------------------------------------------------------------------
|
||
|
// 定数その2
|
||
|
//
|
||
|
#define FM_PI 3.14159265358979323846
|
||
|
|
||
|
#define FM_SINEPRESIS 2 // EGとサイン波の精度の差 0(低)-2(高)
|
||
|
|
||
|
|
||
|
#define FM_OPSINBITS 10
|
||
|
#define FM_OPSINENTS (1 << FM_OPSINBITS)
|
||
|
|
||
|
#define FM_EGCBITS 18 // eg の count のシフト値
|
||
|
#define FM_LFOCBITS 14
|
||
|
|
||
|
#ifdef FM_TUNEBUILD
|
||
|
#define FM_PGBITS 2
|
||
|
#define FM_RATIOBITS 0
|
||
|
#else
|
||
|
#define FM_PGBITS 9
|
||
|
#define FM_RATIOBITS 7 // 8-12 くらいまで?
|
||
|
#endif
|
||
|
|
||
|
#define FM_EGBITS 16
|
||
|
|
||
|
//extern int paramcount[];
|
||
|
//#define PARAMCHANGE(i) paramcount[i]++;
|
||
|
#define PARAMCHANGE(i)
|
||
|
|
||
|
namespace FM
|
||
|
{
|
||
|
|
||
|
// ---------------------------------------------------------------------------
|
||
|
// Operator
|
||
|
//
|
||
|
// フィードバックバッファをクリア
|
||
|
inline void Operator::ResetFB()
|
||
|
{
|
||
|
out_ = out2_ = 0;
|
||
|
}
|
||
|
|
||
|
// キーオン
|
||
|
inline void Operator::KeyOn()
|
||
|
{
|
||
|
if (!keyon_)
|
||
|
{
|
||
|
keyon_ = true;
|
||
|
held_ = false;
|
||
|
if (eg_phase_ == off || eg_phase_ == release)
|
||
|
{
|
||
|
#if 1 // libOPNMIDI: experimental SSG-EG
|
||
|
inverted_ = (ssg_type_ & 4) != 0;
|
||
|
inverted_ ^= (ssg_type_ & 2) && ar_ != 62; // try to match polarity with nuked OPN
|
||
|
#else
|
||
|
ssg_phase_ = -1;
|
||
|
#endif
|
||
|
ShiftPhase(attack);
|
||
|
EGUpdate();
|
||
|
in2_ = out_ = out2_ = 0;
|
||
|
pg_count_ = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// キーオフ
|
||
|
inline void Operator::KeyOff()
|
||
|
{
|
||
|
if (keyon_)
|
||
|
{
|
||
|
keyon_ = false;
|
||
|
ShiftPhase(release);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// オペレータは稼働中か?
|
||
|
inline int Operator::IsOn()
|
||
|
{
|
||
|
return eg_phase_ - off;
|
||
|
}
|
||
|
|
||
|
// Detune (0-7)
|
||
|
inline void Operator::SetDT(uint dt)
|
||
|
{
|
||
|
detune_ = dt * 0x20, param_changed_ = true;
|
||
|
PARAMCHANGE(4);
|
||
|
}
|
||
|
|
||
|
// DT2 (0-3)
|
||
|
inline void Operator::SetDT2(uint dt2)
|
||
|
{
|
||
|
detune2_ = dt2 & 3, param_changed_ = true;
|
||
|
PARAMCHANGE(5);
|
||
|
}
|
||
|
|
||
|
// Multiple (0-15)
|
||
|
inline void Operator::SetMULTI(uint mul)
|
||
|
{
|
||
|
multiple_ = mul, param_changed_ = true;
|
||
|
PARAMCHANGE(6);
|
||
|
}
|
||
|
|
||
|
// Total Level (0-127) (0.75dB step)
|
||
|
inline void Operator::SetTL(uint tl, bool csm)
|
||
|
{
|
||
|
if (!csm)
|
||
|
{
|
||
|
tl_ = tl, param_changed_ = true;
|
||
|
PARAMCHANGE(7);
|
||
|
}
|
||
|
tl_latch_ = tl;
|
||
|
}
|
||
|
|
||
|
// Attack Rate (0-63)
|
||
|
inline void Operator::SetAR(uint ar)
|
||
|
{
|
||
|
ar_ = ar;
|
||
|
param_changed_ = true;
|
||
|
PARAMCHANGE(8);
|
||
|
}
|
||
|
|
||
|
// Decay Rate (0-63)
|
||
|
inline void Operator::SetDR(uint dr)
|
||
|
{
|
||
|
dr_ = dr;
|
||
|
param_changed_ = true;
|
||
|
PARAMCHANGE(9);
|
||
|
}
|
||
|
|
||
|
// Sustain Rate (0-63)
|
||
|
inline void Operator::SetSR(uint sr)
|
||
|
{
|
||
|
sr_ = sr;
|
||
|
param_changed_ = true;
|
||
|
PARAMCHANGE(10);
|
||
|
}
|
||
|
|
||
|
// Sustain Level (0-127)
|
||
|
inline void Operator::SetSL(uint sl)
|
||
|
{
|
||
|
sl_ = sl;
|
||
|
param_changed_ = true;
|
||
|
PARAMCHANGE(11);
|
||
|
}
|
||
|
|
||
|
// Release Rate (0-63)
|
||
|
inline void Operator::SetRR(uint rr)
|
||
|
{
|
||
|
rr_ = rr;
|
||
|
param_changed_ = true;
|
||
|
PARAMCHANGE(12);
|
||
|
}
|
||
|
|
||
|
// Keyscale (0-3)
|
||
|
inline void Operator::SetKS(uint ks)
|
||
|
{
|
||
|
ks_ = ks;
|
||
|
param_changed_ = true;
|
||
|
PARAMCHANGE(13);
|
||
|
}
|
||
|
|
||
|
// SSG-type Envelop (0-15)
|
||
|
inline void Operator::SetSSGEC(uint ssgec)
|
||
|
{
|
||
|
if (ssgec & 8)
|
||
|
ssg_type_ = ssgec;
|
||
|
else
|
||
|
ssg_type_ = 0;
|
||
|
}
|
||
|
|
||
|
inline void Operator::SetAMON(bool amon)
|
||
|
{
|
||
|
amon_ = amon;
|
||
|
param_changed_ = true;
|
||
|
PARAMCHANGE(14);
|
||
|
}
|
||
|
|
||
|
inline void Operator::Mute(bool mute)
|
||
|
{
|
||
|
mute_ = mute;
|
||
|
param_changed_ = true;
|
||
|
PARAMCHANGE(15);
|
||
|
}
|
||
|
|
||
|
inline void Operator::SetMS(uint ms)
|
||
|
{
|
||
|
ms_ = ms;
|
||
|
param_changed_ = true;
|
||
|
PARAMCHANGE(16);
|
||
|
}
|
||
|
|
||
|
// ---------------------------------------------------------------------------
|
||
|
// 4-op Channel
|
||
|
|
||
|
// オペレータの種類 (LFO) を設定
|
||
|
inline void Channel4::SetType(OpType type)
|
||
|
{
|
||
|
for (int i=0; i<4; i++)
|
||
|
op[i].type_ = type;
|
||
|
}
|
||
|
|
||
|
// セルフ・フィードバックレートの設定 (0-7)
|
||
|
inline void Channel4::SetFB(uint feedback)
|
||
|
{
|
||
|
fb = fbtable[feedback];
|
||
|
}
|
||
|
|
||
|
// OPNA 系 LFO の設定
|
||
|
inline void Channel4::SetMS(uint ms)
|
||
|
{
|
||
|
op[0].SetMS(ms);
|
||
|
op[1].SetMS(ms);
|
||
|
op[2].SetMS(ms);
|
||
|
op[3].SetMS(ms);
|
||
|
}
|
||
|
|
||
|
// チャンネル・マスク
|
||
|
inline void Channel4::Mute(bool m)
|
||
|
{
|
||
|
for (int i=0; i<4; i++)
|
||
|
op[i].Mute(m);
|
||
|
}
|
||
|
|
||
|
// 内部パラメータを再計算
|
||
|
inline void Channel4::Refresh()
|
||
|
{
|
||
|
for (int i=0; i<4; i++)
|
||
|
op[i].param_changed_ = true;
|
||
|
PARAMCHANGE(3);
|
||
|
}
|
||
|
|
||
|
inline void Channel4::SetChip(Chip* chip)
|
||
|
{
|
||
|
chip_ = chip;
|
||
|
for (int i=0; i<4; i++)
|
||
|
op[i].SetChip(chip);
|
||
|
}
|
||
|
|
||
|
// ---------------------------------------------------------------------------
|
||
|
//
|
||
|
//
|
||
|
inline void StoreSample(Sample& dest, ISample data)
|
||
|
{
|
||
|
if (sizeof(Sample) == 2)
|
||
|
dest = (Sample) Limit(dest + data, 0x7fff, -0x8000);
|
||
|
else
|
||
|
dest += data;
|
||
|
}
|
||
|
|
||
|
|
||
|
// ---------------------------------------------------------------------------
|
||
|
// AM のレベルを設定
|
||
|
inline void Chip::SetAML(uint l)
|
||
|
{
|
||
|
aml_ = l & (FM_LFOENTS - 1);
|
||
|
}
|
||
|
|
||
|
// PM のレベルを設定
|
||
|
inline void Chip::SetPML(uint l)
|
||
|
{
|
||
|
pml_ = l & (FM_LFOENTS - 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
#endif // FM_GEN_INL_H
|