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