root / hw / fmopl.c @ 546fa6ab
History | View | Annotate | Download (35 kB)
1 |
/*
|
---|---|
2 |
**
|
3 |
** File: fmopl.c -- software implementation of FM sound generator
|
4 |
**
|
5 |
** Copyright (C) 1999,2000 Tatsuyuki Satoh , MultiArcadeMachineEmurator development
|
6 |
**
|
7 |
** Version 0.37a
|
8 |
**
|
9 |
*/
|
10 |
|
11 |
/*
|
12 |
preliminary :
|
13 |
Problem :
|
14 |
note:
|
15 |
*/
|
16 |
|
17 |
/* This version of fmopl.c is a fork of the MAME one, relicensed under the LGPL.
|
18 |
*
|
19 |
* This library is free software; you can redistribute it and/or
|
20 |
* modify it under the terms of the GNU Lesser General Public
|
21 |
* License as published by the Free Software Foundation; either
|
22 |
* version 2.1 of the License, or (at your option) any later version.
|
23 |
*
|
24 |
* This library is distributed in the hope that it will be useful,
|
25 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
26 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
27 |
* Lesser General Public License for more details.
|
28 |
*
|
29 |
* You should have received a copy of the GNU Lesser General Public
|
30 |
* License along with this library; if not, write to the Free Software
|
31 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
32 |
*/
|
33 |
|
34 |
#define INLINE __inline
|
35 |
#define HAS_YM3812 1 |
36 |
|
37 |
#include <stdio.h> |
38 |
#include <stdlib.h> |
39 |
#include <string.h> |
40 |
#include <stdarg.h> |
41 |
#include <math.h> |
42 |
//#include "driver.h" /* use M.A.M.E. */
|
43 |
#include "fmopl.h" |
44 |
|
45 |
#ifndef PI
|
46 |
#define PI 3.14159265358979323846 |
47 |
#endif
|
48 |
|
49 |
/* -------------------- for debug --------------------- */
|
50 |
/* #define OPL_OUTPUT_LOG */
|
51 |
#ifdef OPL_OUTPUT_LOG
|
52 |
static FILE *opl_dbg_fp = NULL; |
53 |
static FM_OPL *opl_dbg_opl[16]; |
54 |
static int opl_dbg_maxchip,opl_dbg_chip; |
55 |
#endif
|
56 |
|
57 |
/* -------------------- preliminary define section --------------------- */
|
58 |
/* attack/decay rate time rate */
|
59 |
#define OPL_ARRATE 141280 /* RATE 4 = 2826.24ms @ 3.6MHz */ |
60 |
#define OPL_DRRATE 1956000 /* RATE 4 = 39280.64ms @ 3.6MHz */ |
61 |
|
62 |
#define DELTAT_MIXING_LEVEL (1) /* DELTA-T ADPCM MIXING LEVEL */ |
63 |
|
64 |
#define FREQ_BITS 24 /* frequency turn */ |
65 |
|
66 |
/* counter bits = 20 , octerve 7 */
|
67 |
#define FREQ_RATE (1<<(FREQ_BITS-20)) |
68 |
#define TL_BITS (FREQ_BITS+2) |
69 |
|
70 |
/* final output shift , limit minimum and maximum */
|
71 |
#define OPL_OUTSB (TL_BITS+3-16) /* OPL output final shift 16bit */ |
72 |
#define OPL_MAXOUT (0x7fff<<OPL_OUTSB) |
73 |
#define OPL_MINOUT (-0x8000<<OPL_OUTSB) |
74 |
|
75 |
/* -------------------- quality selection --------------------- */
|
76 |
|
77 |
/* sinwave entries */
|
78 |
/* used static memory = SIN_ENT * 4 (byte) */
|
79 |
#define SIN_ENT 2048 |
80 |
|
81 |
/* output level entries (envelope,sinwave) */
|
82 |
/* envelope counter lower bits */
|
83 |
#define ENV_BITS 16 |
84 |
/* envelope output entries */
|
85 |
#define EG_ENT 4096 |
86 |
/* used dynamic memory = EG_ENT*4*4(byte)or EG_ENT*6*4(byte) */
|
87 |
/* used static memory = EG_ENT*4 (byte) */
|
88 |
|
89 |
#define EG_OFF ((2*EG_ENT)<<ENV_BITS) /* OFF */ |
90 |
#define EG_DED EG_OFF
|
91 |
#define EG_DST (EG_ENT<<ENV_BITS) /* DECAY START */ |
92 |
#define EG_AED EG_DST
|
93 |
#define EG_AST 0 /* ATTACK START */ |
94 |
|
95 |
#define EG_STEP (96.0/EG_ENT) /* OPL is 0.1875 dB step */ |
96 |
|
97 |
/* LFO table entries */
|
98 |
#define VIB_ENT 512 |
99 |
#define VIB_SHIFT (32-9) |
100 |
#define AMS_ENT 512 |
101 |
#define AMS_SHIFT (32-9) |
102 |
|
103 |
#define VIB_RATE 256 |
104 |
|
105 |
/* -------------------- local defines , macros --------------------- */
|
106 |
|
107 |
/* register number to channel number , slot offset */
|
108 |
#define SLOT1 0 |
109 |
#define SLOT2 1 |
110 |
|
111 |
/* envelope phase */
|
112 |
#define ENV_MOD_RR 0x00 |
113 |
#define ENV_MOD_DR 0x01 |
114 |
#define ENV_MOD_AR 0x02 |
115 |
|
116 |
/* -------------------- tables --------------------- */
|
117 |
static const int slot_array[32]= |
118 |
{ |
119 |
0, 2, 4, 1, 3, 5,-1,-1, |
120 |
6, 8,10, 7, 9,11,-1,-1, |
121 |
12,14,16,13,15,17,-1,-1, |
122 |
-1,-1,-1,-1,-1,-1,-1,-1 |
123 |
}; |
124 |
|
125 |
/* key scale level */
|
126 |
/* table is 3dB/OCT , DV converts this in TL step at 6dB/OCT */
|
127 |
#define DV (EG_STEP/2) |
128 |
static const UINT32 KSL_TABLE[8*16]= |
129 |
{ |
130 |
/* OCT 0 */
|
131 |
0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, |
132 |
0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, |
133 |
0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, |
134 |
0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, |
135 |
/* OCT 1 */
|
136 |
0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, |
137 |
0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, |
138 |
0.000/DV, 0.750/DV, 1.125/DV, 1.500/DV, |
139 |
1.875/DV, 2.250/DV, 2.625/DV, 3.000/DV, |
140 |
/* OCT 2 */
|
141 |
0.000/DV, 0.000/DV, 0.000/DV, 0.000/DV, |
142 |
0.000/DV, 1.125/DV, 1.875/DV, 2.625/DV, |
143 |
3.000/DV, 3.750/DV, 4.125/DV, 4.500/DV, |
144 |
4.875/DV, 5.250/DV, 5.625/DV, 6.000/DV, |
145 |
/* OCT 3 */
|
146 |
0.000/DV, 0.000/DV, 0.000/DV, 1.875/DV, |
147 |
3.000/DV, 4.125/DV, 4.875/DV, 5.625/DV, |
148 |
6.000/DV, 6.750/DV, 7.125/DV, 7.500/DV, |
149 |
7.875/DV, 8.250/DV, 8.625/DV, 9.000/DV, |
150 |
/* OCT 4 */
|
151 |
0.000/DV, 0.000/DV, 3.000/DV, 4.875/DV, |
152 |
6.000/DV, 7.125/DV, 7.875/DV, 8.625/DV, |
153 |
9.000/DV, 9.750/DV,10.125/DV,10.500/DV, |
154 |
10.875/DV,11.250/DV,11.625/DV,12.000/DV, |
155 |
/* OCT 5 */
|
156 |
0.000/DV, 3.000/DV, 6.000/DV, 7.875/DV, |
157 |
9.000/DV,10.125/DV,10.875/DV,11.625/DV, |
158 |
12.000/DV,12.750/DV,13.125/DV,13.500/DV, |
159 |
13.875/DV,14.250/DV,14.625/DV,15.000/DV, |
160 |
/* OCT 6 */
|
161 |
0.000/DV, 6.000/DV, 9.000/DV,10.875/DV, |
162 |
12.000/DV,13.125/DV,13.875/DV,14.625/DV, |
163 |
15.000/DV,15.750/DV,16.125/DV,16.500/DV, |
164 |
16.875/DV,17.250/DV,17.625/DV,18.000/DV, |
165 |
/* OCT 7 */
|
166 |
0.000/DV, 9.000/DV,12.000/DV,13.875/DV, |
167 |
15.000/DV,16.125/DV,16.875/DV,17.625/DV, |
168 |
18.000/DV,18.750/DV,19.125/DV,19.500/DV, |
169 |
19.875/DV,20.250/DV,20.625/DV,21.000/DV |
170 |
}; |
171 |
#undef DV
|
172 |
|
173 |
/* sustain lebel table (3db per step) */
|
174 |
/* 0 - 15: 0, 3, 6, 9,12,15,18,21,24,27,30,33,36,39,42,93 (dB)*/
|
175 |
#define SC(db) (db*((3/EG_STEP)*(1<<ENV_BITS)))+EG_DST |
176 |
static const INT32 SL_TABLE[16]={ |
177 |
SC( 0),SC( 1),SC( 2),SC(3 ),SC(4 ),SC(5 ),SC(6 ),SC( 7), |
178 |
SC( 8),SC( 9),SC(10),SC(11),SC(12),SC(13),SC(14),SC(31) |
179 |
}; |
180 |
#undef SC
|
181 |
|
182 |
#define TL_MAX (EG_ENT*2) /* limit(tl + ksr + envelope) + sinwave */ |
183 |
/* TotalLevel : 48 24 12 6 3 1.5 0.75 (dB) */
|
184 |
/* TL_TABLE[ 0 to TL_MAX ] : plus section */
|
185 |
/* TL_TABLE[ TL_MAX to TL_MAX+TL_MAX-1 ] : minus section */
|
186 |
static INT32 *TL_TABLE;
|
187 |
|
188 |
/* pointers to TL_TABLE with sinwave output offset */
|
189 |
static INT32 **SIN_TABLE;
|
190 |
|
191 |
/* LFO table */
|
192 |
static INT32 *AMS_TABLE;
|
193 |
static INT32 *VIB_TABLE;
|
194 |
|
195 |
/* envelope output curve table */
|
196 |
/* attack + decay + OFF */
|
197 |
static INT32 ENV_CURVE[2*EG_ENT+1]; |
198 |
|
199 |
/* multiple table */
|
200 |
#define ML 2 |
201 |
static const UINT32 MUL_TABLE[16]= { |
202 |
/* 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15 */
|
203 |
0.50*ML, 1.00*ML, 2.00*ML, 3.00*ML, 4.00*ML, 5.00*ML, 6.00*ML, 7.00*ML, |
204 |
8.00*ML, 9.00*ML,10.00*ML,10.00*ML,12.00*ML,12.00*ML,15.00*ML,15.00*ML |
205 |
}; |
206 |
#undef ML
|
207 |
|
208 |
/* dummy attack / decay rate ( when rate == 0 ) */
|
209 |
static INT32 RATE_0[16]= |
210 |
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; |
211 |
|
212 |
/* -------------------- static state --------------------- */
|
213 |
|
214 |
/* lock level of common table */
|
215 |
static int num_lock = 0; |
216 |
|
217 |
/* work table */
|
218 |
static void *cur_chip = NULL; /* current chip point */ |
219 |
/* currenct chip state */
|
220 |
/* static OPLSAMPLE *bufL,*bufR; */
|
221 |
static OPL_CH *S_CH;
|
222 |
static OPL_CH *E_CH;
|
223 |
OPL_SLOT *SLOT7_1,*SLOT7_2,*SLOT8_1,*SLOT8_2; |
224 |
|
225 |
static INT32 outd[1]; |
226 |
static INT32 ams;
|
227 |
static INT32 vib;
|
228 |
INT32 *ams_table; |
229 |
INT32 *vib_table; |
230 |
static INT32 amsIncr;
|
231 |
static INT32 vibIncr;
|
232 |
static INT32 feedback2; /* connect for SLOT 2 */ |
233 |
|
234 |
/* log output level */
|
235 |
#define LOG_ERR 3 /* ERROR */ |
236 |
#define LOG_WAR 2 /* WARNING */ |
237 |
#define LOG_INF 1 /* INFORMATION */ |
238 |
|
239 |
//#define LOG_LEVEL LOG_INF
|
240 |
#define LOG_LEVEL LOG_ERR
|
241 |
|
242 |
//#define LOG(n,x) if( (n)>=LOG_LEVEL ) logerror x
|
243 |
#define LOG(n,x)
|
244 |
|
245 |
/* --------------------- subroutines --------------------- */
|
246 |
|
247 |
INLINE int Limit( int val, int max, int min ) { |
248 |
if ( val > max )
|
249 |
val = max; |
250 |
else if ( val < min ) |
251 |
val = min; |
252 |
|
253 |
return val;
|
254 |
} |
255 |
|
256 |
/* status set and IRQ handling */
|
257 |
INLINE void OPL_STATUS_SET(FM_OPL *OPL,int flag) |
258 |
{ |
259 |
/* set status flag */
|
260 |
OPL->status |= flag; |
261 |
if(!(OPL->status & 0x80)) |
262 |
{ |
263 |
if(OPL->status & OPL->statusmask)
|
264 |
{ /* IRQ on */
|
265 |
OPL->status |= 0x80;
|
266 |
/* callback user interrupt handler (IRQ is OFF to ON) */
|
267 |
if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,1); |
268 |
} |
269 |
} |
270 |
} |
271 |
|
272 |
/* status reset and IRQ handling */
|
273 |
INLINE void OPL_STATUS_RESET(FM_OPL *OPL,int flag) |
274 |
{ |
275 |
/* reset status flag */
|
276 |
OPL->status &=~flag; |
277 |
if((OPL->status & 0x80)) |
278 |
{ |
279 |
if (!(OPL->status & OPL->statusmask) )
|
280 |
{ |
281 |
OPL->status &= 0x7f;
|
282 |
/* callback user interrupt handler (IRQ is ON to OFF) */
|
283 |
if(OPL->IRQHandler) (OPL->IRQHandler)(OPL->IRQParam,0); |
284 |
} |
285 |
} |
286 |
} |
287 |
|
288 |
/* IRQ mask set */
|
289 |
INLINE void OPL_STATUSMASK_SET(FM_OPL *OPL,int flag) |
290 |
{ |
291 |
OPL->statusmask = flag; |
292 |
/* IRQ handling check */
|
293 |
OPL_STATUS_SET(OPL,0);
|
294 |
OPL_STATUS_RESET(OPL,0);
|
295 |
} |
296 |
|
297 |
/* ----- key on ----- */
|
298 |
INLINE void OPL_KEYON(OPL_SLOT *SLOT)
|
299 |
{ |
300 |
/* sin wave restart */
|
301 |
SLOT->Cnt = 0;
|
302 |
/* set attack */
|
303 |
SLOT->evm = ENV_MOD_AR; |
304 |
SLOT->evs = SLOT->evsa; |
305 |
SLOT->evc = EG_AST; |
306 |
SLOT->eve = EG_AED; |
307 |
} |
308 |
/* ----- key off ----- */
|
309 |
INLINE void OPL_KEYOFF(OPL_SLOT *SLOT)
|
310 |
{ |
311 |
if( SLOT->evm > ENV_MOD_RR)
|
312 |
{ |
313 |
/* set envelope counter from envleope output */
|
314 |
SLOT->evm = ENV_MOD_RR; |
315 |
if( !(SLOT->evc&EG_DST) )
|
316 |
//SLOT->evc = (ENV_CURVE[SLOT->evc>>ENV_BITS]<<ENV_BITS) + EG_DST;
|
317 |
SLOT->evc = EG_DST; |
318 |
SLOT->eve = EG_DED; |
319 |
SLOT->evs = SLOT->evsr; |
320 |
} |
321 |
} |
322 |
|
323 |
/* ---------- calcrate Envelope Generator & Phase Generator ---------- */
|
324 |
/* return : envelope output */
|
325 |
INLINE UINT32 OPL_CALC_SLOT( OPL_SLOT *SLOT ) |
326 |
{ |
327 |
/* calcrate envelope generator */
|
328 |
if( (SLOT->evc+=SLOT->evs) >= SLOT->eve )
|
329 |
{ |
330 |
switch( SLOT->evm ){
|
331 |
case ENV_MOD_AR: /* ATTACK -> DECAY1 */ |
332 |
/* next DR */
|
333 |
SLOT->evm = ENV_MOD_DR; |
334 |
SLOT->evc = EG_DST; |
335 |
SLOT->eve = SLOT->SL; |
336 |
SLOT->evs = SLOT->evsd; |
337 |
break;
|
338 |
case ENV_MOD_DR: /* DECAY -> SL or RR */ |
339 |
SLOT->evc = SLOT->SL; |
340 |
SLOT->eve = EG_DED; |
341 |
if(SLOT->eg_typ)
|
342 |
{ |
343 |
SLOT->evs = 0;
|
344 |
} |
345 |
else
|
346 |
{ |
347 |
SLOT->evm = ENV_MOD_RR; |
348 |
SLOT->evs = SLOT->evsr; |
349 |
} |
350 |
break;
|
351 |
case ENV_MOD_RR: /* RR -> OFF */ |
352 |
SLOT->evc = EG_OFF; |
353 |
SLOT->eve = EG_OFF+1;
|
354 |
SLOT->evs = 0;
|
355 |
break;
|
356 |
} |
357 |
} |
358 |
/* calcrate envelope */
|
359 |
return SLOT->TLL+ENV_CURVE[SLOT->evc>>ENV_BITS]+(SLOT->ams ? ams : 0); |
360 |
} |
361 |
|
362 |
/* set algorythm connection */
|
363 |
static void set_algorythm( OPL_CH *CH) |
364 |
{ |
365 |
INT32 *carrier = &outd[0];
|
366 |
CH->connect1 = CH->CON ? carrier : &feedback2; |
367 |
CH->connect2 = carrier; |
368 |
} |
369 |
|
370 |
/* ---------- frequency counter for operater update ---------- */
|
371 |
INLINE void CALC_FCSLOT(OPL_CH *CH,OPL_SLOT *SLOT)
|
372 |
{ |
373 |
int ksr;
|
374 |
|
375 |
/* frequency step counter */
|
376 |
SLOT->Incr = CH->fc * SLOT->mul; |
377 |
ksr = CH->kcode >> SLOT->KSR; |
378 |
|
379 |
if( SLOT->ksr != ksr )
|
380 |
{ |
381 |
SLOT->ksr = ksr; |
382 |
/* attack , decay rate recalcration */
|
383 |
SLOT->evsa = SLOT->AR[ksr]; |
384 |
SLOT->evsd = SLOT->DR[ksr]; |
385 |
SLOT->evsr = SLOT->RR[ksr]; |
386 |
} |
387 |
SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); |
388 |
} |
389 |
|
390 |
/* set multi,am,vib,EG-TYP,KSR,mul */
|
391 |
INLINE void set_mul(FM_OPL *OPL,int slot,int v) |
392 |
{ |
393 |
OPL_CH *CH = &OPL->P_CH[slot/2];
|
394 |
OPL_SLOT *SLOT = &CH->SLOT[slot&1];
|
395 |
|
396 |
SLOT->mul = MUL_TABLE[v&0x0f];
|
397 |
SLOT->KSR = (v&0x10) ? 0 : 2; |
398 |
SLOT->eg_typ = (v&0x20)>>5; |
399 |
SLOT->vib = (v&0x40);
|
400 |
SLOT->ams = (v&0x80);
|
401 |
CALC_FCSLOT(CH,SLOT); |
402 |
} |
403 |
|
404 |
/* set ksl & tl */
|
405 |
INLINE void set_ksl_tl(FM_OPL *OPL,int slot,int v) |
406 |
{ |
407 |
OPL_CH *CH = &OPL->P_CH[slot/2];
|
408 |
OPL_SLOT *SLOT = &CH->SLOT[slot&1];
|
409 |
int ksl = v>>6; /* 0 / 1.5 / 3 / 6 db/OCT */ |
410 |
|
411 |
SLOT->ksl = ksl ? 3-ksl : 31; |
412 |
SLOT->TL = (v&0x3f)*(0.75/EG_STEP); /* 0.75db step */ |
413 |
|
414 |
if( !(OPL->mode&0x80) ) |
415 |
{ /* not CSM latch total level */
|
416 |
SLOT->TLL = SLOT->TL + (CH->ksl_base>>SLOT->ksl); |
417 |
} |
418 |
} |
419 |
|
420 |
/* set attack rate & decay rate */
|
421 |
INLINE void set_ar_dr(FM_OPL *OPL,int slot,int v) |
422 |
{ |
423 |
OPL_CH *CH = &OPL->P_CH[slot/2];
|
424 |
OPL_SLOT *SLOT = &CH->SLOT[slot&1];
|
425 |
int ar = v>>4; |
426 |
int dr = v&0x0f; |
427 |
|
428 |
SLOT->AR = ar ? &OPL->AR_TABLE[ar<<2] : RATE_0;
|
429 |
SLOT->evsa = SLOT->AR[SLOT->ksr]; |
430 |
if( SLOT->evm == ENV_MOD_AR ) SLOT->evs = SLOT->evsa;
|
431 |
|
432 |
SLOT->DR = dr ? &OPL->DR_TABLE[dr<<2] : RATE_0;
|
433 |
SLOT->evsd = SLOT->DR[SLOT->ksr]; |
434 |
if( SLOT->evm == ENV_MOD_DR ) SLOT->evs = SLOT->evsd;
|
435 |
} |
436 |
|
437 |
/* set sustain level & release rate */
|
438 |
INLINE void set_sl_rr(FM_OPL *OPL,int slot,int v) |
439 |
{ |
440 |
OPL_CH *CH = &OPL->P_CH[slot/2];
|
441 |
OPL_SLOT *SLOT = &CH->SLOT[slot&1];
|
442 |
int sl = v>>4; |
443 |
int rr = v & 0x0f; |
444 |
|
445 |
SLOT->SL = SL_TABLE[sl]; |
446 |
if( SLOT->evm == ENV_MOD_DR ) SLOT->eve = SLOT->SL;
|
447 |
SLOT->RR = &OPL->DR_TABLE[rr<<2];
|
448 |
SLOT->evsr = SLOT->RR[SLOT->ksr]; |
449 |
if( SLOT->evm == ENV_MOD_RR ) SLOT->evs = SLOT->evsr;
|
450 |
} |
451 |
|
452 |
/* operator output calcrator */
|
453 |
#define OP_OUT(slot,env,con) slot->wavetable[((slot->Cnt+con)/(0x1000000/SIN_ENT))&(SIN_ENT-1)][env] |
454 |
/* ---------- calcrate one of channel ---------- */
|
455 |
INLINE void OPL_CALC_CH( OPL_CH *CH )
|
456 |
{ |
457 |
UINT32 env_out; |
458 |
OPL_SLOT *SLOT; |
459 |
|
460 |
feedback2 = 0;
|
461 |
/* SLOT 1 */
|
462 |
SLOT = &CH->SLOT[SLOT1]; |
463 |
env_out=OPL_CALC_SLOT(SLOT); |
464 |
if( env_out < EG_ENT-1 ) |
465 |
{ |
466 |
/* PG */
|
467 |
if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
|
468 |
else SLOT->Cnt += SLOT->Incr;
|
469 |
/* connectoion */
|
470 |
if(CH->FB)
|
471 |
{ |
472 |
int feedback1 = (CH->op1_out[0]+CH->op1_out[1])>>CH->FB; |
473 |
CH->op1_out[1] = CH->op1_out[0]; |
474 |
*CH->connect1 += CH->op1_out[0] = OP_OUT(SLOT,env_out,feedback1);
|
475 |
} |
476 |
else
|
477 |
{ |
478 |
*CH->connect1 += OP_OUT(SLOT,env_out,0);
|
479 |
} |
480 |
}else
|
481 |
{ |
482 |
CH->op1_out[1] = CH->op1_out[0]; |
483 |
CH->op1_out[0] = 0; |
484 |
} |
485 |
/* SLOT 2 */
|
486 |
SLOT = &CH->SLOT[SLOT2]; |
487 |
env_out=OPL_CALC_SLOT(SLOT); |
488 |
if( env_out < EG_ENT-1 ) |
489 |
{ |
490 |
/* PG */
|
491 |
if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
|
492 |
else SLOT->Cnt += SLOT->Incr;
|
493 |
/* connectoion */
|
494 |
outd[0] += OP_OUT(SLOT,env_out, feedback2);
|
495 |
} |
496 |
} |
497 |
|
498 |
/* ---------- calcrate rythm block ---------- */
|
499 |
#define WHITE_NOISE_db 6.0 |
500 |
INLINE void OPL_CALC_RH( OPL_CH *CH )
|
501 |
{ |
502 |
UINT32 env_tam,env_sd,env_top,env_hh; |
503 |
int whitenoise = (rand()&1)*(WHITE_NOISE_db/EG_STEP); |
504 |
INT32 tone8; |
505 |
|
506 |
OPL_SLOT *SLOT; |
507 |
int env_out;
|
508 |
|
509 |
/* BD : same as FM serial mode and output level is large */
|
510 |
feedback2 = 0;
|
511 |
/* SLOT 1 */
|
512 |
SLOT = &CH[6].SLOT[SLOT1];
|
513 |
env_out=OPL_CALC_SLOT(SLOT); |
514 |
if( env_out < EG_ENT-1 ) |
515 |
{ |
516 |
/* PG */
|
517 |
if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
|
518 |
else SLOT->Cnt += SLOT->Incr;
|
519 |
/* connectoion */
|
520 |
if(CH[6].FB) |
521 |
{ |
522 |
int feedback1 = (CH[6].op1_out[0]+CH[6].op1_out[1])>>CH[6].FB; |
523 |
CH[6].op1_out[1] = CH[6].op1_out[0]; |
524 |
feedback2 = CH[6].op1_out[0] = OP_OUT(SLOT,env_out,feedback1); |
525 |
} |
526 |
else
|
527 |
{ |
528 |
feedback2 = OP_OUT(SLOT,env_out,0);
|
529 |
} |
530 |
}else
|
531 |
{ |
532 |
feedback2 = 0;
|
533 |
CH[6].op1_out[1] = CH[6].op1_out[0]; |
534 |
CH[6].op1_out[0] = 0; |
535 |
} |
536 |
/* SLOT 2 */
|
537 |
SLOT = &CH[6].SLOT[SLOT2];
|
538 |
env_out=OPL_CALC_SLOT(SLOT); |
539 |
if( env_out < EG_ENT-1 ) |
540 |
{ |
541 |
/* PG */
|
542 |
if(SLOT->vib) SLOT->Cnt += (SLOT->Incr*vib/VIB_RATE);
|
543 |
else SLOT->Cnt += SLOT->Incr;
|
544 |
/* connectoion */
|
545 |
outd[0] += OP_OUT(SLOT,env_out, feedback2)*2; |
546 |
} |
547 |
|
548 |
// SD (17) = mul14[fnum7] + white noise
|
549 |
// TAM (15) = mul15[fnum8]
|
550 |
// TOP (18) = fnum6(mul18[fnum8]+whitenoise)
|
551 |
// HH (14) = fnum7(mul18[fnum8]+whitenoise) + white noise
|
552 |
env_sd =OPL_CALC_SLOT(SLOT7_2) + whitenoise; |
553 |
env_tam=OPL_CALC_SLOT(SLOT8_1); |
554 |
env_top=OPL_CALC_SLOT(SLOT8_2); |
555 |
env_hh =OPL_CALC_SLOT(SLOT7_1) + whitenoise; |
556 |
|
557 |
/* PG */
|
558 |
if(SLOT7_1->vib) SLOT7_1->Cnt += (2*SLOT7_1->Incr*vib/VIB_RATE); |
559 |
else SLOT7_1->Cnt += 2*SLOT7_1->Incr; |
560 |
if(SLOT7_2->vib) SLOT7_2->Cnt += ((CH[7].fc*8)*vib/VIB_RATE); |
561 |
else SLOT7_2->Cnt += (CH[7].fc*8); |
562 |
if(SLOT8_1->vib) SLOT8_1->Cnt += (SLOT8_1->Incr*vib/VIB_RATE);
|
563 |
else SLOT8_1->Cnt += SLOT8_1->Incr;
|
564 |
if(SLOT8_2->vib) SLOT8_2->Cnt += ((CH[8].fc*48)*vib/VIB_RATE); |
565 |
else SLOT8_2->Cnt += (CH[8].fc*48); |
566 |
|
567 |
tone8 = OP_OUT(SLOT8_2,whitenoise,0 );
|
568 |
|
569 |
/* SD */
|
570 |
if( env_sd < EG_ENT-1 ) |
571 |
outd[0] += OP_OUT(SLOT7_1,env_sd, 0)*8; |
572 |
/* TAM */
|
573 |
if( env_tam < EG_ENT-1 ) |
574 |
outd[0] += OP_OUT(SLOT8_1,env_tam, 0)*2; |
575 |
/* TOP-CY */
|
576 |
if( env_top < EG_ENT-1 ) |
577 |
outd[0] += OP_OUT(SLOT7_2,env_top,tone8)*2; |
578 |
/* HH */
|
579 |
if( env_hh < EG_ENT-1 ) |
580 |
outd[0] += OP_OUT(SLOT7_2,env_hh,tone8)*2; |
581 |
} |
582 |
|
583 |
/* ----------- initialize time tabls ----------- */
|
584 |
static void init_timetables( FM_OPL *OPL , int ARRATE , int DRRATE ) |
585 |
{ |
586 |
int i;
|
587 |
double rate;
|
588 |
|
589 |
/* make attack rate & decay rate tables */
|
590 |
for (i = 0;i < 4;i++) OPL->AR_TABLE[i] = OPL->DR_TABLE[i] = 0; |
591 |
for (i = 4;i <= 60;i++){ |
592 |
rate = OPL->freqbase; /* frequency rate */
|
593 |
if( i < 60 ) rate *= 1.0+(i&3)*0.25; /* b0-1 : x1 , x1.25 , x1.5 , x1.75 */ |
594 |
rate *= 1<<((i>>2)-1); /* b2-5 : shift bit */ |
595 |
rate *= (double)(EG_ENT<<ENV_BITS);
|
596 |
OPL->AR_TABLE[i] = rate / ARRATE; |
597 |
OPL->DR_TABLE[i] = rate / DRRATE; |
598 |
} |
599 |
for (i = 60;i < 76;i++) |
600 |
{ |
601 |
OPL->AR_TABLE[i] = EG_AED-1;
|
602 |
OPL->DR_TABLE[i] = OPL->DR_TABLE[60];
|
603 |
} |
604 |
#if 0
|
605 |
for (i = 0;i < 64 ;i++){ /* make for overflow area */
|
606 |
LOG(LOG_WAR,("rate %2d , ar %f ms , dr %f ms \n",i,
|
607 |
((double)(EG_ENT<<ENV_BITS) / OPL->AR_TABLE[i]) * (1000.0 / OPL->rate),
|
608 |
((double)(EG_ENT<<ENV_BITS) / OPL->DR_TABLE[i]) * (1000.0 / OPL->rate) ));
|
609 |
}
|
610 |
#endif
|
611 |
} |
612 |
|
613 |
/* ---------- generic table initialize ---------- */
|
614 |
static int OPLOpenTable( void ) |
615 |
{ |
616 |
int s,t;
|
617 |
double rate;
|
618 |
int i,j;
|
619 |
double pom;
|
620 |
|
621 |
/* allocate dynamic tables */
|
622 |
if( (TL_TABLE = malloc(TL_MAX*2*sizeof(INT32))) == NULL) |
623 |
return 0; |
624 |
if( (SIN_TABLE = malloc(SIN_ENT*4 *sizeof(INT32 *))) == NULL) |
625 |
{ |
626 |
free(TL_TABLE); |
627 |
return 0; |
628 |
} |
629 |
if( (AMS_TABLE = malloc(AMS_ENT*2 *sizeof(INT32))) == NULL) |
630 |
{ |
631 |
free(TL_TABLE); |
632 |
free(SIN_TABLE); |
633 |
return 0; |
634 |
} |
635 |
if( (VIB_TABLE = malloc(VIB_ENT*2 *sizeof(INT32))) == NULL) |
636 |
{ |
637 |
free(TL_TABLE); |
638 |
free(SIN_TABLE); |
639 |
free(AMS_TABLE); |
640 |
return 0; |
641 |
} |
642 |
/* make total level table */
|
643 |
for (t = 0;t < EG_ENT-1 ;t++){ |
644 |
rate = ((1<<TL_BITS)-1)/pow(10,EG_STEP*t/20); /* dB -> voltage */ |
645 |
TL_TABLE[ t] = (int)rate;
|
646 |
TL_TABLE[TL_MAX+t] = -TL_TABLE[t]; |
647 |
/* LOG(LOG_INF,("TotalLevel(%3d) = %x\n",t,TL_TABLE[t]));*/
|
648 |
} |
649 |
/* fill volume off area */
|
650 |
for ( t = EG_ENT-1; t < TL_MAX ;t++){ |
651 |
TL_TABLE[t] = TL_TABLE[TL_MAX+t] = 0;
|
652 |
} |
653 |
|
654 |
/* make sinwave table (total level offet) */
|
655 |
/* degree 0 = degree 180 = off */
|
656 |
SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2] = &TL_TABLE[EG_ENT-1]; |
657 |
for (s = 1;s <= SIN_ENT/4;s++){ |
658 |
pom = sin(2*PI*s/SIN_ENT); /* sin */ |
659 |
pom = 20*log10(1/pom); /* decibel */ |
660 |
j = pom / EG_STEP; /* TL_TABLE steps */
|
661 |
|
662 |
/* degree 0 - 90 , degree 180 - 90 : plus section */
|
663 |
SIN_TABLE[ s] = SIN_TABLE[SIN_ENT/2-s] = &TL_TABLE[j];
|
664 |
/* degree 180 - 270 , degree 360 - 270 : minus section */
|
665 |
SIN_TABLE[SIN_ENT/2+s] = SIN_TABLE[SIN_ENT -s] = &TL_TABLE[TL_MAX+j];
|
666 |
/* LOG(LOG_INF,("sin(%3d) = %f:%f db\n",s,pom,(double)j * EG_STEP));*/
|
667 |
} |
668 |
for (s = 0;s < SIN_ENT;s++) |
669 |
{ |
670 |
SIN_TABLE[SIN_ENT*1+s] = s<(SIN_ENT/2) ? SIN_TABLE[s] : &TL_TABLE[EG_ENT]; |
671 |
SIN_TABLE[SIN_ENT*2+s] = SIN_TABLE[s % (SIN_ENT/2)]; |
672 |
SIN_TABLE[SIN_ENT*3+s] = (s/(SIN_ENT/4))&1 ? &TL_TABLE[EG_ENT] : SIN_TABLE[SIN_ENT*2+s]; |
673 |
} |
674 |
|
675 |
/* envelope counter -> envelope output table */
|
676 |
for (i=0; i<EG_ENT; i++) |
677 |
{ |
678 |
/* ATTACK curve */
|
679 |
pom = pow( ((double)(EG_ENT-1-i)/EG_ENT) , 8 ) * EG_ENT; |
680 |
/* if( pom >= EG_ENT ) pom = EG_ENT-1; */
|
681 |
ENV_CURVE[i] = (int)pom;
|
682 |
/* DECAY ,RELEASE curve */
|
683 |
ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i; |
684 |
} |
685 |
/* off */
|
686 |
ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1;
|
687 |
/* make LFO ams table */
|
688 |
for (i=0; i<AMS_ENT; i++) |
689 |
{ |
690 |
pom = (1.0+sin(2*PI*i/AMS_ENT))/2; /* sin */ |
691 |
AMS_TABLE[i] = (1.0/EG_STEP)*pom; /* 1dB */ |
692 |
AMS_TABLE[AMS_ENT+i] = (4.8/EG_STEP)*pom; /* 4.8dB */ |
693 |
} |
694 |
/* make LFO vibrate table */
|
695 |
for (i=0; i<VIB_ENT; i++) |
696 |
{ |
697 |
/* 100cent = 1seminote = 6% ?? */
|
698 |
pom = (double)VIB_RATE*0.06*sin(2*PI*i/VIB_ENT); /* +-100sect step */ |
699 |
VIB_TABLE[i] = VIB_RATE + (pom*0.07); /* +- 7cent */ |
700 |
VIB_TABLE[VIB_ENT+i] = VIB_RATE + (pom*0.14); /* +-14cent */ |
701 |
/* LOG(LOG_INF,("vib %d=%d\n",i,VIB_TABLE[VIB_ENT+i])); */
|
702 |
} |
703 |
return 1; |
704 |
} |
705 |
|
706 |
|
707 |
static void OPLCloseTable( void ) |
708 |
{ |
709 |
free(TL_TABLE); |
710 |
free(SIN_TABLE); |
711 |
free(AMS_TABLE); |
712 |
free(VIB_TABLE); |
713 |
} |
714 |
|
715 |
/* CSM Key Controll */
|
716 |
INLINE void CSMKeyControll(OPL_CH *CH)
|
717 |
{ |
718 |
OPL_SLOT *slot1 = &CH->SLOT[SLOT1]; |
719 |
OPL_SLOT *slot2 = &CH->SLOT[SLOT2]; |
720 |
/* all key off */
|
721 |
OPL_KEYOFF(slot1); |
722 |
OPL_KEYOFF(slot2); |
723 |
/* total level latch */
|
724 |
slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl); |
725 |
slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl); |
726 |
/* key on */
|
727 |
CH->op1_out[0] = CH->op1_out[1] = 0; |
728 |
OPL_KEYON(slot1); |
729 |
OPL_KEYON(slot2); |
730 |
} |
731 |
|
732 |
/* ---------- opl initialize ---------- */
|
733 |
static void OPL_initalize(FM_OPL *OPL) |
734 |
{ |
735 |
int fn;
|
736 |
|
737 |
/* frequency base */
|
738 |
OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / OPL->rate) / 72 : 0; |
739 |
/* Timer base time */
|
740 |
OPL->TimerBase = 1.0/((double)OPL->clock / 72.0 ); |
741 |
/* make time tables */
|
742 |
init_timetables( OPL , OPL_ARRATE , OPL_DRRATE ); |
743 |
/* make fnumber -> increment counter table */
|
744 |
for( fn=0 ; fn < 1024 ; fn++ ) |
745 |
{ |
746 |
OPL->FN_TABLE[fn] = OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2; |
747 |
} |
748 |
/* LFO freq.table */
|
749 |
OPL->amsIncr = OPL->rate ? (double)AMS_ENT*(1<<AMS_SHIFT) / OPL->rate * 3.7 * ((double)OPL->clock/3600000) : 0; |
750 |
OPL->vibIncr = OPL->rate ? (double)VIB_ENT*(1<<VIB_SHIFT) / OPL->rate * 6.4 * ((double)OPL->clock/3600000) : 0; |
751 |
} |
752 |
|
753 |
/* ---------- write a OPL registers ---------- */
|
754 |
static void OPLWriteReg(FM_OPL *OPL, int r, int v) |
755 |
{ |
756 |
OPL_CH *CH; |
757 |
int slot;
|
758 |
int block_fnum;
|
759 |
|
760 |
switch(r&0xe0) |
761 |
{ |
762 |
case 0x00: /* 00-1f:controll */ |
763 |
switch(r&0x1f) |
764 |
{ |
765 |
case 0x01: |
766 |
/* wave selector enable */
|
767 |
if(OPL->type&OPL_TYPE_WAVESEL)
|
768 |
{ |
769 |
OPL->wavesel = v&0x20;
|
770 |
if(!OPL->wavesel)
|
771 |
{ |
772 |
/* preset compatible mode */
|
773 |
int c;
|
774 |
for(c=0;c<OPL->max_ch;c++) |
775 |
{ |
776 |
OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0];
|
777 |
OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0];
|
778 |
} |
779 |
} |
780 |
} |
781 |
return;
|
782 |
case 0x02: /* Timer 1 */ |
783 |
OPL->T[0] = (256-v)*4; |
784 |
break;
|
785 |
case 0x03: /* Timer 2 */ |
786 |
OPL->T[1] = (256-v)*16; |
787 |
return;
|
788 |
case 0x04: /* IRQ clear / mask and Timer enable */ |
789 |
if(v&0x80) |
790 |
{ /* IRQ flag clear */
|
791 |
OPL_STATUS_RESET(OPL,0x7f);
|
792 |
} |
793 |
else
|
794 |
{ /* set IRQ mask ,timer enable*/
|
795 |
UINT8 st1 = v&1;
|
796 |
UINT8 st2 = (v>>1)&1; |
797 |
/* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */
|
798 |
OPL_STATUS_RESET(OPL,v&0x78);
|
799 |
OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01); |
800 |
/* timer 2 */
|
801 |
if(OPL->st[1] != st2) |
802 |
{ |
803 |
double interval = st2 ? (double)OPL->T[1]*OPL->TimerBase : 0.0; |
804 |
OPL->st[1] = st2;
|
805 |
if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval); |
806 |
} |
807 |
/* timer 1 */
|
808 |
if(OPL->st[0] != st1) |
809 |
{ |
810 |
double interval = st1 ? (double)OPL->T[0]*OPL->TimerBase : 0.0; |
811 |
OPL->st[0] = st1;
|
812 |
if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval); |
813 |
} |
814 |
} |
815 |
return;
|
816 |
#if BUILD_Y8950
|
817 |
case 0x06: /* Key Board OUT */ |
818 |
if(OPL->type&OPL_TYPE_KEYBOARD)
|
819 |
{ |
820 |
if(OPL->keyboardhandler_w)
|
821 |
OPL->keyboardhandler_w(OPL->keyboard_param,v); |
822 |
else
|
823 |
LOG(LOG_WAR,("OPL:write unmapped KEYBOARD port\n"));
|
824 |
} |
825 |
return;
|
826 |
case 0x07: /* DELTA-T controll : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */ |
827 |
if(OPL->type&OPL_TYPE_ADPCM)
|
828 |
YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
|
829 |
return;
|
830 |
case 0x08: /* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */ |
831 |
OPL->mode = v; |
832 |
v&=0x1f; /* for DELTA-T unit */ |
833 |
case 0x09: /* START ADD */ |
834 |
case 0x0a: |
835 |
case 0x0b: /* STOP ADD */ |
836 |
case 0x0c: |
837 |
case 0x0d: /* PRESCALE */ |
838 |
case 0x0e: |
839 |
case 0x0f: /* ADPCM data */ |
840 |
case 0x10: /* DELTA-N */ |
841 |
case 0x11: /* DELTA-N */ |
842 |
case 0x12: /* EG-CTRL */ |
843 |
if(OPL->type&OPL_TYPE_ADPCM)
|
844 |
YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
|
845 |
return;
|
846 |
#if 0
|
847 |
case 0x15: /* DAC data */
|
848 |
case 0x16:
|
849 |
case 0x17: /* SHIFT */
|
850 |
return;
|
851 |
case 0x18: /* I/O CTRL (Direction) */
|
852 |
if(OPL->type&OPL_TYPE_IO)
|
853 |
OPL->portDirection = v&0x0f;
|
854 |
return;
|
855 |
case 0x19: /* I/O DATA */
|
856 |
if(OPL->type&OPL_TYPE_IO)
|
857 |
{
|
858 |
OPL->portLatch = v;
|
859 |
if(OPL->porthandler_w)
|
860 |
OPL->porthandler_w(OPL->port_param,v&OPL->portDirection);
|
861 |
}
|
862 |
return;
|
863 |
case 0x1a: /* PCM data */
|
864 |
return;
|
865 |
#endif
|
866 |
#endif
|
867 |
} |
868 |
break;
|
869 |
case 0x20: /* am,vib,ksr,eg type,mul */ |
870 |
slot = slot_array[r&0x1f];
|
871 |
if(slot == -1) return; |
872 |
set_mul(OPL,slot,v); |
873 |
return;
|
874 |
case 0x40: |
875 |
slot = slot_array[r&0x1f];
|
876 |
if(slot == -1) return; |
877 |
set_ksl_tl(OPL,slot,v); |
878 |
return;
|
879 |
case 0x60: |
880 |
slot = slot_array[r&0x1f];
|
881 |
if(slot == -1) return; |
882 |
set_ar_dr(OPL,slot,v); |
883 |
return;
|
884 |
case 0x80: |
885 |
slot = slot_array[r&0x1f];
|
886 |
if(slot == -1) return; |
887 |
set_sl_rr(OPL,slot,v); |
888 |
return;
|
889 |
case 0xa0: |
890 |
switch(r)
|
891 |
{ |
892 |
case 0xbd: |
893 |
/* amsep,vibdep,r,bd,sd,tom,tc,hh */
|
894 |
{ |
895 |
UINT8 rkey = OPL->rythm^v; |
896 |
OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0]; |
897 |
OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0]; |
898 |
OPL->rythm = v&0x3f;
|
899 |
if(OPL->rythm&0x20) |
900 |
{ |
901 |
#if 0
|
902 |
usrintf_showmessage("OPL Rythm mode select");
|
903 |
#endif
|
904 |
/* BD key on/off */
|
905 |
if(rkey&0x10) |
906 |
{ |
907 |
if(v&0x10) |
908 |
{ |
909 |
OPL->P_CH[6].op1_out[0] = OPL->P_CH[6].op1_out[1] = 0; |
910 |
OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT1]);
|
911 |
OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT2]);
|
912 |
} |
913 |
else
|
914 |
{ |
915 |
OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1]);
|
916 |
OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2]);
|
917 |
} |
918 |
} |
919 |
/* SD key on/off */
|
920 |
if(rkey&0x08) |
921 |
{ |
922 |
if(v&0x08) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT2]); |
923 |
else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2]); |
924 |
}/* TAM key on/off */
|
925 |
if(rkey&0x04) |
926 |
{ |
927 |
if(v&0x04) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT1]); |
928 |
else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1]); |
929 |
} |
930 |
/* TOP-CY key on/off */
|
931 |
if(rkey&0x02) |
932 |
{ |
933 |
if(v&0x02) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT2]); |
934 |
else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2]); |
935 |
} |
936 |
/* HH key on/off */
|
937 |
if(rkey&0x01) |
938 |
{ |
939 |
if(v&0x01) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT1]); |
940 |
else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1]); |
941 |
} |
942 |
} |
943 |
} |
944 |
return;
|
945 |
} |
946 |
/* keyon,block,fnum */
|
947 |
if( (r&0x0f) > 8) return; |
948 |
CH = &OPL->P_CH[r&0x0f];
|
949 |
if(!(r&0x10)) |
950 |
{ /* a0-a8 */
|
951 |
block_fnum = (CH->block_fnum&0x1f00) | v;
|
952 |
} |
953 |
else
|
954 |
{ /* b0-b8 */
|
955 |
int keyon = (v>>5)&1; |
956 |
block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff); |
957 |
if(CH->keyon != keyon)
|
958 |
{ |
959 |
if( (CH->keyon=keyon) )
|
960 |
{ |
961 |
CH->op1_out[0] = CH->op1_out[1] = 0; |
962 |
OPL_KEYON(&CH->SLOT[SLOT1]); |
963 |
OPL_KEYON(&CH->SLOT[SLOT2]); |
964 |
} |
965 |
else
|
966 |
{ |
967 |
OPL_KEYOFF(&CH->SLOT[SLOT1]); |
968 |
OPL_KEYOFF(&CH->SLOT[SLOT2]); |
969 |
} |
970 |
} |
971 |
} |
972 |
/* update */
|
973 |
if(CH->block_fnum != block_fnum)
|
974 |
{ |
975 |
int blockRv = 7-(block_fnum>>10); |
976 |
int fnum = block_fnum&0x3ff; |
977 |
CH->block_fnum = block_fnum; |
978 |
|
979 |
CH->ksl_base = KSL_TABLE[block_fnum>>6];
|
980 |
CH->fc = OPL->FN_TABLE[fnum]>>blockRv; |
981 |
CH->kcode = CH->block_fnum>>9;
|
982 |
if( (OPL->mode&0x40) && CH->block_fnum&0x100) CH->kcode |=1; |
983 |
CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); |
984 |
CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); |
985 |
} |
986 |
return;
|
987 |
case 0xc0: |
988 |
/* FB,C */
|
989 |
if( (r&0x0f) > 8) return; |
990 |
CH = &OPL->P_CH[r&0x0f];
|
991 |
{ |
992 |
int feedback = (v>>1)&7; |
993 |
CH->FB = feedback ? (8+1) - feedback : 0; |
994 |
CH->CON = v&1;
|
995 |
set_algorythm(CH); |
996 |
} |
997 |
return;
|
998 |
case 0xe0: /* wave type */ |
999 |
slot = slot_array[r&0x1f];
|
1000 |
if(slot == -1) return; |
1001 |
CH = &OPL->P_CH[slot/2];
|
1002 |
if(OPL->wavesel)
|
1003 |
{ |
1004 |
/* LOG(LOG_INF,("OPL SLOT %d wave select %d\n",slot,v&3)); */
|
1005 |
CH->SLOT[slot&1].wavetable = &SIN_TABLE[(v&0x03)*SIN_ENT]; |
1006 |
} |
1007 |
return;
|
1008 |
} |
1009 |
} |
1010 |
|
1011 |
/* lock/unlock for common table */
|
1012 |
static int OPL_LockTable(void) |
1013 |
{ |
1014 |
num_lock++; |
1015 |
if(num_lock>1) return 0; |
1016 |
/* first time */
|
1017 |
cur_chip = NULL;
|
1018 |
/* allocate total level table (128kb space) */
|
1019 |
if( !OPLOpenTable() )
|
1020 |
{ |
1021 |
num_lock--; |
1022 |
return -1; |
1023 |
} |
1024 |
return 0; |
1025 |
} |
1026 |
|
1027 |
static void OPL_UnLockTable(void) |
1028 |
{ |
1029 |
if(num_lock) num_lock--;
|
1030 |
if(num_lock) return; |
1031 |
/* last time */
|
1032 |
cur_chip = NULL;
|
1033 |
OPLCloseTable(); |
1034 |
} |
1035 |
|
1036 |
#if (BUILD_YM3812 || BUILD_YM3526)
|
1037 |
/*******************************************************************************/
|
1038 |
/* YM3812 local section */
|
1039 |
/*******************************************************************************/
|
1040 |
|
1041 |
/* ---------- update one of chip ----------- */
|
1042 |
void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length) |
1043 |
{ |
1044 |
int i;
|
1045 |
int data;
|
1046 |
OPLSAMPLE *buf = buffer; |
1047 |
UINT32 amsCnt = OPL->amsCnt; |
1048 |
UINT32 vibCnt = OPL->vibCnt; |
1049 |
UINT8 rythm = OPL->rythm&0x20;
|
1050 |
OPL_CH *CH,*R_CH; |
1051 |
|
1052 |
if( (void *)OPL != cur_chip ){ |
1053 |
cur_chip = (void *)OPL;
|
1054 |
/* channel pointers */
|
1055 |
S_CH = OPL->P_CH; |
1056 |
E_CH = &S_CH[9];
|
1057 |
/* rythm slot */
|
1058 |
SLOT7_1 = &S_CH[7].SLOT[SLOT1];
|
1059 |
SLOT7_2 = &S_CH[7].SLOT[SLOT2];
|
1060 |
SLOT8_1 = &S_CH[8].SLOT[SLOT1];
|
1061 |
SLOT8_2 = &S_CH[8].SLOT[SLOT2];
|
1062 |
/* LFO state */
|
1063 |
amsIncr = OPL->amsIncr; |
1064 |
vibIncr = OPL->vibIncr; |
1065 |
ams_table = OPL->ams_table; |
1066 |
vib_table = OPL->vib_table; |
1067 |
} |
1068 |
R_CH = rythm ? &S_CH[6] : E_CH;
|
1069 |
for( i=0; i < length ; i++ ) |
1070 |
{ |
1071 |
/* channel A channel B channel C */
|
1072 |
/* LFO */
|
1073 |
ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT]; |
1074 |
vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT]; |
1075 |
outd[0] = 0; |
1076 |
/* FM part */
|
1077 |
for(CH=S_CH ; CH < R_CH ; CH++)
|
1078 |
OPL_CALC_CH(CH); |
1079 |
/* Rythn part */
|
1080 |
if(rythm)
|
1081 |
OPL_CALC_RH(S_CH); |
1082 |
/* limit check */
|
1083 |
data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
|
1084 |
/* store to sound buffer */
|
1085 |
buf[i] = data >> OPL_OUTSB; |
1086 |
} |
1087 |
|
1088 |
OPL->amsCnt = amsCnt; |
1089 |
OPL->vibCnt = vibCnt; |
1090 |
#ifdef OPL_OUTPUT_LOG
|
1091 |
if(opl_dbg_fp)
|
1092 |
{ |
1093 |
for(opl_dbg_chip=0;opl_dbg_chip<opl_dbg_maxchip;opl_dbg_chip++) |
1094 |
if( opl_dbg_opl[opl_dbg_chip] == OPL) break; |
1095 |
fprintf(opl_dbg_fp,"%c%c%c",0x20+opl_dbg_chip,length&0xff,length/256); |
1096 |
} |
1097 |
#endif
|
1098 |
} |
1099 |
#endif /* (BUILD_YM3812 || BUILD_YM3526) */ |
1100 |
|
1101 |
#if BUILD_Y8950
|
1102 |
|
1103 |
void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length) |
1104 |
{ |
1105 |
int i;
|
1106 |
int data;
|
1107 |
OPLSAMPLE *buf = buffer; |
1108 |
UINT32 amsCnt = OPL->amsCnt; |
1109 |
UINT32 vibCnt = OPL->vibCnt; |
1110 |
UINT8 rythm = OPL->rythm&0x20;
|
1111 |
OPL_CH *CH,*R_CH; |
1112 |
YM_DELTAT *DELTAT = OPL->deltat; |
1113 |
|
1114 |
/* setup DELTA-T unit */
|
1115 |
YM_DELTAT_DECODE_PRESET(DELTAT); |
1116 |
|
1117 |
if( (void *)OPL != cur_chip ){ |
1118 |
cur_chip = (void *)OPL;
|
1119 |
/* channel pointers */
|
1120 |
S_CH = OPL->P_CH; |
1121 |
E_CH = &S_CH[9];
|
1122 |
/* rythm slot */
|
1123 |
SLOT7_1 = &S_CH[7].SLOT[SLOT1];
|
1124 |
SLOT7_2 = &S_CH[7].SLOT[SLOT2];
|
1125 |
SLOT8_1 = &S_CH[8].SLOT[SLOT1];
|
1126 |
SLOT8_2 = &S_CH[8].SLOT[SLOT2];
|
1127 |
/* LFO state */
|
1128 |
amsIncr = OPL->amsIncr; |
1129 |
vibIncr = OPL->vibIncr; |
1130 |
ams_table = OPL->ams_table; |
1131 |
vib_table = OPL->vib_table; |
1132 |
} |
1133 |
R_CH = rythm ? &S_CH[6] : E_CH;
|
1134 |
for( i=0; i < length ; i++ ) |
1135 |
{ |
1136 |
/* channel A channel B channel C */
|
1137 |
/* LFO */
|
1138 |
ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT]; |
1139 |
vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT]; |
1140 |
outd[0] = 0; |
1141 |
/* deltaT ADPCM */
|
1142 |
if( DELTAT->portstate )
|
1143 |
YM_DELTAT_ADPCM_CALC(DELTAT); |
1144 |
/* FM part */
|
1145 |
for(CH=S_CH ; CH < R_CH ; CH++)
|
1146 |
OPL_CALC_CH(CH); |
1147 |
/* Rythn part */
|
1148 |
if(rythm)
|
1149 |
OPL_CALC_RH(S_CH); |
1150 |
/* limit check */
|
1151 |
data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
|
1152 |
/* store to sound buffer */
|
1153 |
buf[i] = data >> OPL_OUTSB; |
1154 |
} |
1155 |
OPL->amsCnt = amsCnt; |
1156 |
OPL->vibCnt = vibCnt; |
1157 |
/* deltaT START flag */
|
1158 |
if( !DELTAT->portstate )
|
1159 |
OPL->status &= 0xfe;
|
1160 |
} |
1161 |
#endif
|
1162 |
|
1163 |
/* ---------- reset one of chip ---------- */
|
1164 |
void OPLResetChip(FM_OPL *OPL)
|
1165 |
{ |
1166 |
int c,s;
|
1167 |
int i;
|
1168 |
|
1169 |
/* reset chip */
|
1170 |
OPL->mode = 0; /* normal mode */ |
1171 |
OPL_STATUS_RESET(OPL,0x7f);
|
1172 |
/* reset with register write */
|
1173 |
OPLWriteReg(OPL,0x01,0); /* wabesel disable */ |
1174 |
OPLWriteReg(OPL,0x02,0); /* Timer1 */ |
1175 |
OPLWriteReg(OPL,0x03,0); /* Timer2 */ |
1176 |
OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */ |
1177 |
for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0); |
1178 |
/* reset OPerator paramater */
|
1179 |
for( c = 0 ; c < OPL->max_ch ; c++ ) |
1180 |
{ |
1181 |
OPL_CH *CH = &OPL->P_CH[c]; |
1182 |
/* OPL->P_CH[c].PAN = OPN_CENTER; */
|
1183 |
for(s = 0 ; s < 2 ; s++ ) |
1184 |
{ |
1185 |
/* wave table */
|
1186 |
CH->SLOT[s].wavetable = &SIN_TABLE[0];
|
1187 |
/* CH->SLOT[s].evm = ENV_MOD_RR; */
|
1188 |
CH->SLOT[s].evc = EG_OFF; |
1189 |
CH->SLOT[s].eve = EG_OFF+1;
|
1190 |
CH->SLOT[s].evs = 0;
|
1191 |
} |
1192 |
} |
1193 |
#if BUILD_Y8950
|
1194 |
if(OPL->type&OPL_TYPE_ADPCM)
|
1195 |
{ |
1196 |
YM_DELTAT *DELTAT = OPL->deltat; |
1197 |
|
1198 |
DELTAT->freqbase = OPL->freqbase; |
1199 |
DELTAT->output_pointer = outd; |
1200 |
DELTAT->portshift = 5;
|
1201 |
DELTAT->output_range = DELTAT_MIXING_LEVEL<<TL_BITS; |
1202 |
YM_DELTAT_ADPCM_Reset(DELTAT,0);
|
1203 |
} |
1204 |
#endif
|
1205 |
} |
1206 |
|
1207 |
/* ---------- Create one of vietual YM3812 ---------- */
|
1208 |
/* 'rate' is sampling rate and 'bufsiz' is the size of the */
|
1209 |
FM_OPL *OPLCreate(int type, int clock, int rate) |
1210 |
{ |
1211 |
char *ptr;
|
1212 |
FM_OPL *OPL; |
1213 |
int state_size;
|
1214 |
int max_ch = 9; /* normaly 9 channels */ |
1215 |
|
1216 |
if( OPL_LockTable() ==-1) return NULL; |
1217 |
/* allocate OPL state space */
|
1218 |
state_size = sizeof(FM_OPL);
|
1219 |
state_size += sizeof(OPL_CH)*max_ch;
|
1220 |
#if BUILD_Y8950
|
1221 |
if(type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT); |
1222 |
#endif
|
1223 |
/* allocate memory block */
|
1224 |
ptr = malloc(state_size); |
1225 |
if(ptr==NULL) return NULL; |
1226 |
/* clear */
|
1227 |
memset(ptr,0,state_size);
|
1228 |
OPL = (FM_OPL *)ptr; ptr+=sizeof(FM_OPL);
|
1229 |
OPL->P_CH = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch;
|
1230 |
#if BUILD_Y8950
|
1231 |
if(type&OPL_TYPE_ADPCM) OPL->deltat = (YM_DELTAT *)ptr; ptr+=sizeof(YM_DELTAT); |
1232 |
#endif
|
1233 |
/* set channel state pointer */
|
1234 |
OPL->type = type; |
1235 |
OPL->clock = clock; |
1236 |
OPL->rate = rate; |
1237 |
OPL->max_ch = max_ch; |
1238 |
/* init grobal tables */
|
1239 |
OPL_initalize(OPL); |
1240 |
/* reset chip */
|
1241 |
OPLResetChip(OPL); |
1242 |
#ifdef OPL_OUTPUT_LOG
|
1243 |
if(!opl_dbg_fp)
|
1244 |
{ |
1245 |
opl_dbg_fp = fopen("opllog.opl","wb"); |
1246 |
opl_dbg_maxchip = 0;
|
1247 |
} |
1248 |
if(opl_dbg_fp)
|
1249 |
{ |
1250 |
opl_dbg_opl[opl_dbg_maxchip] = OPL; |
1251 |
fprintf(opl_dbg_fp,"%c%c%c%c%c%c",0x00+opl_dbg_maxchip, |
1252 |
type, |
1253 |
clock&0xff,
|
1254 |
(clock/0x100)&0xff, |
1255 |
(clock/0x10000)&0xff, |
1256 |
(clock/0x1000000)&0xff); |
1257 |
opl_dbg_maxchip++; |
1258 |
} |
1259 |
#endif
|
1260 |
return OPL;
|
1261 |
} |
1262 |
|
1263 |
/* ---------- Destroy one of vietual YM3812 ---------- */
|
1264 |
void OPLDestroy(FM_OPL *OPL)
|
1265 |
{ |
1266 |
#ifdef OPL_OUTPUT_LOG
|
1267 |
if(opl_dbg_fp)
|
1268 |
{ |
1269 |
fclose(opl_dbg_fp); |
1270 |
opl_dbg_fp = NULL;
|
1271 |
} |
1272 |
#endif
|
1273 |
OPL_UnLockTable(); |
1274 |
free(OPL); |
1275 |
} |
1276 |
|
1277 |
/* ---------- Option handlers ---------- */
|
1278 |
|
1279 |
void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset) |
1280 |
{ |
1281 |
OPL->TimerHandler = TimerHandler; |
1282 |
OPL->TimerParam = channelOffset; |
1283 |
} |
1284 |
void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param) |
1285 |
{ |
1286 |
OPL->IRQHandler = IRQHandler; |
1287 |
OPL->IRQParam = param; |
1288 |
} |
1289 |
void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param) |
1290 |
{ |
1291 |
OPL->UpdateHandler = UpdateHandler; |
1292 |
OPL->UpdateParam = param; |
1293 |
} |
1294 |
#if BUILD_Y8950
|
1295 |
void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param) |
1296 |
{ |
1297 |
OPL->porthandler_w = PortHandler_w; |
1298 |
OPL->porthandler_r = PortHandler_r; |
1299 |
OPL->port_param = param; |
1300 |
} |
1301 |
|
1302 |
void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param) |
1303 |
{ |
1304 |
OPL->keyboardhandler_w = KeyboardHandler_w; |
1305 |
OPL->keyboardhandler_r = KeyboardHandler_r; |
1306 |
OPL->keyboard_param = param; |
1307 |
} |
1308 |
#endif
|
1309 |
/* ---------- YM3812 I/O interface ---------- */
|
1310 |
int OPLWrite(FM_OPL *OPL,int a,int v) |
1311 |
{ |
1312 |
if( !(a&1) ) |
1313 |
{ /* address port */
|
1314 |
OPL->address = v & 0xff;
|
1315 |
} |
1316 |
else
|
1317 |
{ /* data port */
|
1318 |
if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); |
1319 |
#ifdef OPL_OUTPUT_LOG
|
1320 |
if(opl_dbg_fp)
|
1321 |
{ |
1322 |
for(opl_dbg_chip=0;opl_dbg_chip<opl_dbg_maxchip;opl_dbg_chip++) |
1323 |
if( opl_dbg_opl[opl_dbg_chip] == OPL) break; |
1324 |
fprintf(opl_dbg_fp,"%c%c%c",0x10+opl_dbg_chip,OPL->address,v); |
1325 |
} |
1326 |
#endif
|
1327 |
OPLWriteReg(OPL,OPL->address,v); |
1328 |
} |
1329 |
return OPL->status>>7; |
1330 |
} |
1331 |
|
1332 |
unsigned char OPLRead(FM_OPL *OPL,int a) |
1333 |
{ |
1334 |
if( !(a&1) ) |
1335 |
{ /* status port */
|
1336 |
return OPL->status & (OPL->statusmask|0x80); |
1337 |
} |
1338 |
/* data port */
|
1339 |
switch(OPL->address)
|
1340 |
{ |
1341 |
case 0x05: /* KeyBoard IN */ |
1342 |
if(OPL->type&OPL_TYPE_KEYBOARD)
|
1343 |
{ |
1344 |
if(OPL->keyboardhandler_r)
|
1345 |
return OPL->keyboardhandler_r(OPL->keyboard_param);
|
1346 |
else
|
1347 |
LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n"));
|
1348 |
} |
1349 |
return 0; |
1350 |
#if 0
|
1351 |
case 0x0f: /* ADPCM-DATA */
|
1352 |
return 0;
|
1353 |
#endif
|
1354 |
case 0x19: /* I/O DATA */ |
1355 |
if(OPL->type&OPL_TYPE_IO)
|
1356 |
{ |
1357 |
if(OPL->porthandler_r)
|
1358 |
return OPL->porthandler_r(OPL->port_param);
|
1359 |
else
|
1360 |
LOG(LOG_WAR,("OPL:read unmapped I/O port\n"));
|
1361 |
} |
1362 |
return 0; |
1363 |
case 0x1a: /* PCM-DATA */ |
1364 |
return 0; |
1365 |
} |
1366 |
return 0; |
1367 |
} |
1368 |
|
1369 |
int OPLTimerOver(FM_OPL *OPL,int c) |
1370 |
{ |
1371 |
if( c )
|
1372 |
{ /* Timer B */
|
1373 |
OPL_STATUS_SET(OPL,0x20);
|
1374 |
} |
1375 |
else
|
1376 |
{ /* Timer A */
|
1377 |
OPL_STATUS_SET(OPL,0x40);
|
1378 |
/* CSM mode key,TL controll */
|
1379 |
if( OPL->mode & 0x80 ) |
1380 |
{ /* CSM mode total level latch and auto key on */
|
1381 |
int ch;
|
1382 |
if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); |
1383 |
for(ch=0;ch<9;ch++) |
1384 |
CSMKeyControll( &OPL->P_CH[ch] ); |
1385 |
} |
1386 |
} |
1387 |
/* reload timer */
|
1388 |
if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase); |
1389 |
return OPL->status>>7; |
1390 |
} |