1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  * LGPL licensed version of MAMEs fmopl (V0.37a modified) by
22  * Tatsuyuki Satoh. Included from LGPL'ed AdPlug.
23  *
24  */
25 
26 
27 #ifndef AUDIO_SOFTSYNTH_OPL_MAME_H
28 #define AUDIO_SOFTSYNTH_OPL_MAME_H
29 
30 #include "common/scummsys.h"
31 #include "common/random.h"
32 
33 #include "audio/fmopl.h"
34 
35 namespace OPL {
36 namespace MAME {
37 
38 enum {
39 	FMOPL_ENV_BITS_HQ = 16,
40 	FMOPL_ENV_BITS_MQ = 8,
41 	FMOPL_ENV_BITS_LQ = 8,
42 	FMOPL_EG_ENT_HQ = 4096,
43 	FMOPL_EG_ENT_MQ = 1024,
44 	FMOPL_EG_ENT_LQ = 128
45 };
46 
47 
48 typedef void (*OPL_TIMERHANDLER)(int channel,double interval_Sec);
49 typedef void (*OPL_IRQHANDLER)(int param,int irq);
50 typedef void (*OPL_UPDATEHANDLER)(int param,int min_interval_us);
51 
52 #define OPL_TYPE_WAVESEL   0x01  /* waveform select    */
53 
54 /* Saving is necessary for member of the 'R' mark for suspend/resume */
55 /* ---------- OPL one of slot  ---------- */
56 typedef struct fm_opl_slot {
57 	int TL;		/* total level     :TL << 8				*/
58 	int TLL;	/* adjusted now TL						*/
59 	uint8 KSR;	/* key scale rate  :(shift down bit)	*/
60 	int *AR;	/* attack rate     :&AR_TABLE[AR<<2]	*/
61 	int *DR;	/* decay rate      :&DR_TABLE[DR<<2]	*/
62 	int SL;		/* sustain level   :SL_TABLE[SL]		*/
63 	int *RR;	/* release rate    :&DR_TABLE[RR<<2]	*/
64 	uint8 ksl;	/* keyscale level  :(shift down bits)	*/
65 	uint8 ksr;	/* key scale rate  :kcode>>KSR			*/
66 	uint mul;	/* multiple        :ML_TABLE[ML]		*/
67 	uint Cnt;	/* frequency count						*/
68 	uint Incr;	/* frequency step						*/
69 
70 	/* envelope generator state */
71 	uint8 eg_typ;/* envelope type flag					*/
72 	uint8 evm;	/* envelope phase						*/
73 	int evc;	/* envelope counter						*/
74 	int eve;	/* envelope counter end point			*/
75 	int evs;	/* envelope counter step				*/
76 	int evsa;	/* envelope step for AR :AR[ksr]		*/
77 	int evsd;	/* envelope step for DR :DR[ksr]		*/
78 	int evsr;	/* envelope step for RR :RR[ksr]		*/
79 
80 	/* LFO */
81 	uint8 ams;		/* ams flag                            */
82 	uint8 vib;		/* vibrate flag                        */
83 	/* wave selector */
84 	int **wavetable;
85 } OPL_SLOT;
86 
87 /* ---------- OPL one of channel  ---------- */
88 typedef struct fm_opl_channel {
89 	OPL_SLOT SLOT[2];
90 	uint8 CON;			/* connection type					*/
91 	uint8 FB;			/* feed back       :(shift down bit)*/
92 	int *connect1;		/* slot1 output pointer				*/
93 	int *connect2;		/* slot2 output pointer				*/
94 	int op1_out[2];		/* slot1 output for selfeedback		*/
95 
96 	/* phase generator state */
97 	uint block_fnum;	/* block+fnum						*/
98 	uint8 kcode;		/* key code        : KeyScaleCode	*/
99 	uint fc;			/* Freq. Increment base				*/
100 	uint ksl_base;		/* KeyScaleLevel Base step			*/
101 	uint8 keyon;		/* key on/off flag					*/
102 } OPL_CH;
103 
104 /* OPL state */
105 typedef struct fm_opl_f {
106 	uint8 type;			/* chip type                         */
107 	int clock;			/* master clock  (Hz)                */
108 	int rate;			/* sampling rate (Hz)                */
109 	double freqbase;	/* frequency base                    */
110 	double TimerBase;	/* Timer base time (==sampling time) */
111 	uint8 address;		/* address register                  */
112 	uint8 status;		/* status flag                       */
113 	uint8 statusmask;	/* status mask                       */
114 	uint mode;			/* Reg.08 : CSM , notesel,etc.       */
115 
116 	/* Timer */
117 	int T[2];			/* timer counter                     */
118 	uint8 st[2];		/* timer enable                      */
119 
120 	/* FM channel slots */
121 	OPL_CH *P_CH;		/* pointer of CH                     */
122 	int	max_ch;			/* maximum channel                   */
123 
124 	/* Rythm sention */
125 	uint8 rythm;		/* Rythm mode , key flag */
126 
127 	/* time tables */
128 	int AR_TABLE[76];	/* atttack rate tables				*/
129 	int DR_TABLE[76];	/* decay rate tables				*/
130 	uint FN_TABLE[1024];/* fnumber -> increment counter		*/
131 
132 	/* LFO */
133 	int *ams_table;
134 	int *vib_table;
135 	int amsCnt;
136 	int amsIncr;
137 	int vibCnt;
138 	int vibIncr;
139 
140 	/* wave selector enable flag */
141 	uint8 wavesel;
142 
143 	/* external event callback handler */
144 	OPL_TIMERHANDLER  TimerHandler;		/* TIMER handler   */
145 	int TimerParam;						/* TIMER parameter */
146 	OPL_IRQHANDLER    IRQHandler;		/* IRQ handler    */
147 	int IRQParam;						/* IRQ parameter  */
148 	OPL_UPDATEHANDLER UpdateHandler;	/* stream update handler   */
149 	int UpdateParam;					/* stream update parameter */
150 
151 	Common::RandomSource *rnd;
152 } FM_OPL;
153 
154 /* ---------- Generic interface section ---------- */
155 #define OPL_TYPE_YM3526 (0)
156 #define OPL_TYPE_YM3812 (OPL_TYPE_WAVESEL)
157 
158 void OPLBuildTables(int ENV_BITS_PARAM, int EG_ENT_PARAM);
159 
160 FM_OPL *OPLCreate(int type, int clock, int rate);
161 void OPLDestroy(FM_OPL *OPL);
162 void OPLSetTimerHandler(FM_OPL *OPL, OPL_TIMERHANDLER TimerHandler, int channelOffset);
163 void OPLSetIRQHandler(FM_OPL *OPL, OPL_IRQHANDLER IRQHandler, int param);
164 void OPLSetUpdateHandler(FM_OPL *OPL, OPL_UPDATEHANDLER UpdateHandler, int param);
165 
166 void OPLResetChip(FM_OPL *OPL);
167 int OPLWrite(FM_OPL *OPL, int a, int v);
168 unsigned char OPLRead(FM_OPL *OPL, int a);
169 int OPLTimerOver(FM_OPL *OPL, int c);
170 void OPLWriteReg(FM_OPL *OPL, int r, int v);
171 void YM3812UpdateOne(FM_OPL *OPL, int16 *buffer, int length);
172 
173 // Factory method
174 FM_OPL *makeAdLibOPL(int rate);
175 
176 // OPL API implementation
177 class OPL : public ::OPL::EmulatedOPL {
178 private:
179 	FM_OPL *_opl;
180 public:
OPL()181 	OPL() : _opl(0) {}
182 	~OPL();
183 
184 	bool init();
185 	void reset();
186 
187 	void write(int a, int v);
188 	byte read(int a);
189 
190 	void writeReg(int r, int v);
191 
isStereo()192 	bool isStereo() const { return false; }
193 
194 protected:
195 	void generateSamples(int16 *buffer, int length);
196 };
197 
198 } // End of namespace MAME
199 } // End of namespace OPL
200 
201 #endif
202