1 // ---------------------------------------------------------------------------
2 // OPN/A/B interface with ADPCM support
3 // Copyright (C) cisc 1998, 2003.
4 // ---------------------------------------------------------------------------
5 // $Id: opna.h,v 1.33 2003/06/12 13:14:37 cisc Exp $
10 #include "../../common.h"
15 // ---------------------------------------------------------------------------
17 // OPN/OPNA に良く似た音を生成する音源ユニット
20 // bool Init(uint clock, uint rate, bool, const _TCHAR* path);
21 // 初期化.このクラスを使用する前にかならず呼んでおくこと.
22 // OPNA の場合はこの関数でリズムサンプルを読み込む
24 // clock: OPN/OPNA/OPNB のクロック周波数(Hz)
26 // rate: 生成する PCM の標本周波数(Hz)
28 // path: リズムサンプルのパス(OPNA のみ有効)
29 // 省略時はカレントディレクトリから読み込む
30 // 文字列の末尾には '\' や '/' などをつけること
34 // bool LoadRhythmSample(const _TCHAR* path)
37 // path は Init の path と同じ.
39 // bool SetRate(uint clock, uint rate, bool)
43 // void Mix(FM_SAMPLETYPE* dest, int nsamples)
44 // Stereo PCM データを nsamples 分合成し, dest で始まる配列に
46 // ・dest には sample*2 個分の領域が必要
47 // ・格納形式は L, R, L, R... となる.
48 // ・あくまで加算なので,あらかじめ配列をゼロクリアする必要がある
49 // ・FM_SAMPLETYPE が short 型の場合クリッピングが行われる.
50 // ・この関数は音源内部のタイマーとは独立している.
51 // Timer は Count と GetNextEvent で操作する必要がある.
56 // void SetReg(uint reg, uint data)
57 // 音源のレジスタ reg に data を書き込む
59 // uint GetReg(uint reg)
60 // 音源のレジスタ reg の内容を読み出す
61 // 読み込むことが出来るレジスタは PSG, ADPCM の一部,ID(0xff) とか
63 // uint ReadStatus()/ReadStatusEx()
65 // ReadStatusEx は拡張ステータスレジスタの読み出し(OPNA)
71 // bool Count(uint32 t)
72 // 音源のタイマーを t [clock] 進める.
73 // 音源の内部状態に変化があった時(timer オーバーフロー)
76 // uint32 GetNextEvent()
77 // 音源のタイマーのどちらかがオーバーフローするまでに必要な
79 // タイマーが停止している場合は ULONG_MAX を返す… と思う
81 // void SetVolumeFM(int db_l, int db_r)/SetVolumePSG(int db_l, int db_r) ...
82 // 各音源の音量を+−方向に調節する.標準値は 0.
83 // 単位は約 1/2 dB,有効範囲の上限は 20 (10dB)
88 // OPN Base -------------------------------------------------------
89 class DLL_PREFIX OPNBase : public Timer
97 bool Init(uint c, uint r);
101 void SetVolumeFM(int db_l, int db_r);
102 void SetVolumePSG(int db_l, int db_r);
103 void SetLPFCutoff(uint freq) {} // obsolete
104 uint GetPrescaler() { return prescale; }
108 void SetParameter(Channel4* ch, uint addr, uint data);
109 virtual void SetPrescaler(uint p);
110 void RebuildTimeTable();
111 void Intr(bool value);
113 bool ProcessState(void *f, bool loading);
118 uint clock; // OPN クロック
119 uint rate; // FM 音源合成レート
120 uint psgrate; // FMGen 出力レート
126 __DECL_ALIGNED(16) static uint32 lfotable[8];
136 // OPNA Base ------------------------------------------------------
137 class DLL_PREFIX OPNABase : public OPNBase
143 uint ReadStatus() { return status & 0x03; }
145 void SetChannelMask(uint mask);
151 bool Init(uint c, uint r, bool);
152 bool SetRate(uint c, uint r, bool);
155 void SetReg(uint addr, uint data);
156 void SetADPCMBReg(uint reg, uint data);
157 uint GetReg(uint addr);
159 bool ProcessState(void *f, bool loading);
162 void FMMix(Sample* buffer, int nsamples);
163 void Mix6(Sample* buffer, int nsamples, int activech);
165 void MixSubS(int activech, ISample**);
166 void MixSubSL(int activech, ISample**);
168 void SetStatus(uint bit);
169 void ResetStatus(uint bit);
174 void ADPCMBMix(Sample* dest, uint count);
176 void WriteRAM(uint data);
179 int DecodeADPCMBSample(uint);
182 __DECL_ALIGNED(16) uint8 pan[6];
183 __DECL_ALIGNED(16) uint8 fnum2[9];
186 uint reg29; // OPNA only?
194 __DECL_ALIGNED(16) uint fnum[6];
195 __DECL_ALIGNED(16) uint fnum3[3];
198 uint8* adpcmbuf; // ADPCM RAM
199 uint adpcmmask; // メモリアドレスに対するビットマスク
200 uint adpcmnotice; // ADPCM 再生終了時にたつビット
201 uint startaddr; // Start address
202 uint stopaddr; // Stop address
203 uint memaddr; // 再生中アドレス
204 uint limitaddr; // Limit address/mask
205 int adpcmlevel; // ADPCM 音量
211 int adplc; // 周波数変換用変数
212 int adpld; // 周波数変換用変数差分値
213 uint adplbase; // adpld の元
214 int adpcmx; // ADPCM 合成用 x
215 int adpcmd; // ADPCM 合成用
216 int adpcmout_l; // ADPCM 合成後の出力
217 int adpcmout_r; // ADPCM 合成後の出力
218 int apout0_l; // out(t-2)+out(t-1)
219 int apout0_r; // out(t-2)+out(t-1)
220 int apout1_l; // out(t-1)+out(t)
221 int apout1_r; // out(t-1)+out(t)
223 uint adpcmreadbuf; // ADPCM リード用バッファ
224 bool adpcmplay; // ADPCM 再生中
228 uint8 control1; // ADPCM コントロールレジスタ1
229 uint8 control2; // ADPCM コントロールレジスタ2
230 __DECL_ALIGNED(16) uint8 adpcmreg[8]; // ADPCM レジスタの一部分
234 __DECL_ALIGNED(16) Channel4 ch[6];
236 static void BuildLFOTable();
237 __DECL_ALIGNED(16) static int amtable[FM_LFOENTS];
238 __DECL_ALIGNED(16) static int pmtable[FM_LFOENTS];
239 __DECL_ALIGNED(16) static int32 tltable[FM_TLENTS+FM_TLPOS];
240 static bool tablehasmade;
243 // OPN2 Base ------------------------------------------------------
244 class DLL_PREFIX OPN2Base : public OPNBase
250 uint ReadStatus() { return status & 0x7f; }
251 uint ReadStatusEx() { return 0xff; }
252 void SetChannelMask(uint mask);
258 bool Init(uint c, uint r, bool);
259 bool SetRate(uint c, uint r, bool);
260 virtual void SetPrescaler(uint p);
263 void SetReg(uint addr, uint data);
264 uint GetReg(uint addr);
266 bool ProcessState(void *f, bool loading);
269 void FMMix(Sample* buffer, int nsamples);
270 void Mix6(Sample* buffer, int nsamples, int activech);
272 void MixSubS(int activech, ISample**);
273 void MixSubSL(int activech, ISample**);
275 void SetStatus(uint bit);
276 void ResetStatus(uint bit);
281 __DECL_ALIGNED(16) uint8 pan[6];
282 __DECL_ALIGNED(16) uint8 fnum2[9];
285 uint reg29; // OPNA only?
292 __DECL_ALIGNED(16) uint fnum[6];
293 __DECL_ALIGNED(16) uint fnum3[3];
295 __DECL_ALIGNED(16) Channel4 ch[6];
299 static void BuildLFOTable();
300 __DECL_ALIGNED(16) static int amtable[FM_LFOENTS];
301 __DECL_ALIGNED(16) static int pmtable[FM_LFOENTS];
302 __DECL_ALIGNED(16) static int32 tltable[FM_TLENTS+FM_TLPOS];
303 static bool tablehasmade;
305 // YM2203(OPN) ----------------------------------------------------
306 class DLL_PREFIX OPN : public OPNBase
312 bool Init(uint c, uint r, bool=false, const char* =0);
313 bool SetRate(uint c, uint r, bool=false);
316 void Mix(Sample* buffer, int nsamples);
317 void SetReg(uint addr, uint data);
318 uint GetReg(uint addr);
319 uint ReadStatus() { return status & 0x03; }
320 uint ReadStatusEx() { return 0xff; }
322 void SetChannelMask(uint mask);
324 int dbgGetOpOut(int c, int s) { return ch[c].op[s].dbgopout_; }
325 int dbgGetPGOut(int c, int s) { return ch[c].op[s].dbgpgout_; }
326 Channel4* dbgGetCh(int c) { return &ch[c]; }
328 bool ProcessState(void *f, bool loading);
331 void SetStatus(uint bit);
332 void ResetStatus(uint bit);
334 __DECL_ALIGNED(16) uint fnum[3];
335 __DECL_ALIGNED(16) uint fnum3[3];
336 __DECL_ALIGNED(16) uint8 fnum2[6];
338 __DECL_ALIGNED(16) Channel4 ch[3];
341 // YM2608(OPNA) ---------------------------------------------------
342 class DLL_PREFIX OPNA : public OPNABase
348 bool Init(uint c, uint r, bool = false, const _TCHAR* rhythmpath=0);
349 bool LoadRhythmSample(const _TCHAR*);
351 bool SetRate(uint c, uint r, bool = false);
352 void Mix(Sample* buffer, int nsamples);
355 void SetReg(uint addr, uint data);
356 uint GetReg(uint addr);
358 void SetVolumeADPCM(int db_l, int db_r);
359 void SetVolumeRhythmTotal(int db_l, int db_r);
360 void SetVolumeRhythm(int index, int db_l, int db_r);
362 uint8* GetADPCMBuffer() { return adpcmbuf; }
364 int dbgGetOpOut(int c, int s) { return ch[c].op[s].dbgopout_; }
365 int dbgGetPGOut(int c, int s) { return ch[c].op[s].dbgpgout_; }
366 Channel4* dbgGetCh(int c) { return &ch[c]; }
368 bool ProcessState(void *f, bool loading);
375 int volume_l; // おんりょうせってい
376 int volume_r; // おんりょうせってい
377 int16* sample; // さんぷる
381 uint rate; // さんぷるのれーと
384 void RhythmMix(Sample* buffer, uint count);
387 __DECL_ALIGNED(16) Rhythm rhythm[6];
388 int8 rhythmtl; // リズム全体の音量
391 uint8 rhythmkey; // リズムのキー
394 // YM2610/B(OPNB) ---------------------------------------------------
395 class DLL_PREFIX OPNB : public OPNABase
401 bool Init(uint c, uint r, bool = false,
402 uint8 *_adpcma = 0, int _adpcma_size = 0,
403 uint8 *_adpcmb = 0, int _adpcmb_size = 0);
405 bool SetRate(uint c, uint r, bool = false);
406 void Mix(Sample* buffer, int nsamples);
409 void SetReg(uint addr, uint data);
410 uint GetReg(uint addr);
413 void SetVolumeADPCMATotal(int db_l, int db_r);
414 void SetVolumeADPCMA(int index, int db_l, int db_r);
415 void SetVolumeADPCMB(int db_l, int db_r);
417 // void SetChannelMask(uint mask);
424 int volume_l; // おんりょうせってい
425 int volume_r; // おんりょうせってい
431 uint nibble; // 次の 4 bit
436 int DecodeADPCMASample(uint);
437 void ADPCMAMix(Sample* buffer, uint count);
438 static void InitADPCMATable();
441 uint8* adpcmabuf; // ADPCMA ROM
443 __DECL_ALIGNED(16) ADPCMA adpcma[6];
444 int8 adpcmatl; // ADPCMA 全体の音量
447 uint8 adpcmakey; // ADPCMA のキー
449 __DECL_ALIGNED(16) uint8 adpcmareg[32];
451 __DECL_ALIGNED(16) static int jedi_table[(48+1)*16];
453 __DECL_ALIGNED(16) Channel4 ch[6];
456 // YM2612/3438(OPN2) ----------------------------------------------------
457 class DLL_PREFIX OPN2 : public OPN2Base
463 bool Init(uint c, uint r, bool=false, const char* =0);
464 bool SetRate(uint c, uint r, bool);
467 void Mix(Sample* buffer, int nsamples);
468 void SetReg(uint addr, uint data);
469 uint GetReg(uint addr);
470 uint ReadStatus() { return status & 0x03; }
471 uint ReadStatusEx() { return 0xff; }
473 bool ProcessState(void *f, bool loading);
476 //void SetStatus(uint bit);
477 //void ResetStatus(uint bit);
483 // ---------------------------------------------------------------------------
485 inline void FM::OPNBase::RebuildTimeTable()
492 inline void FM::OPNBase::SetVolumePSG(int db_l, int db_r)
494 psg.SetVolume(db_l, db_r, is_ay3_891x);