root / hw / fmopl.c @ 487414f1
History | View | Annotate | Download (34.8 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
|
32 |
*/
|
33 |
|
34 |
#define INLINE static 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 |
TL_TABLE = qemu_malloc(TL_MAX*2*sizeof(INT32)); |
623 |
SIN_TABLE = qemu_malloc(SIN_ENT*4 *sizeof(INT32 *)); |
624 |
AMS_TABLE = qemu_malloc(AMS_ENT*2 *sizeof(INT32)); |
625 |
VIB_TABLE = qemu_malloc(VIB_ENT*2 *sizeof(INT32)); |
626 |
/* make total level table */
|
627 |
for (t = 0;t < EG_ENT-1 ;t++){ |
628 |
rate = ((1<<TL_BITS)-1)/pow(10,EG_STEP*t/20); /* dB -> voltage */ |
629 |
TL_TABLE[ t] = (int)rate;
|
630 |
TL_TABLE[TL_MAX+t] = -TL_TABLE[t]; |
631 |
/* LOG(LOG_INF,("TotalLevel(%3d) = %x\n",t,TL_TABLE[t]));*/
|
632 |
} |
633 |
/* fill volume off area */
|
634 |
for ( t = EG_ENT-1; t < TL_MAX ;t++){ |
635 |
TL_TABLE[t] = TL_TABLE[TL_MAX+t] = 0;
|
636 |
} |
637 |
|
638 |
/* make sinwave table (total level offet) */
|
639 |
/* degree 0 = degree 180 = off */
|
640 |
SIN_TABLE[0] = SIN_TABLE[SIN_ENT/2] = &TL_TABLE[EG_ENT-1]; |
641 |
for (s = 1;s <= SIN_ENT/4;s++){ |
642 |
pom = sin(2*PI*s/SIN_ENT); /* sin */ |
643 |
pom = 20*log10(1/pom); /* decibel */ |
644 |
j = pom / EG_STEP; /* TL_TABLE steps */
|
645 |
|
646 |
/* degree 0 - 90 , degree 180 - 90 : plus section */
|
647 |
SIN_TABLE[ s] = SIN_TABLE[SIN_ENT/2-s] = &TL_TABLE[j];
|
648 |
/* degree 180 - 270 , degree 360 - 270 : minus section */
|
649 |
SIN_TABLE[SIN_ENT/2+s] = SIN_TABLE[SIN_ENT -s] = &TL_TABLE[TL_MAX+j];
|
650 |
/* LOG(LOG_INF,("sin(%3d) = %f:%f db\n",s,pom,(double)j * EG_STEP));*/
|
651 |
} |
652 |
for (s = 0;s < SIN_ENT;s++) |
653 |
{ |
654 |
SIN_TABLE[SIN_ENT*1+s] = s<(SIN_ENT/2) ? SIN_TABLE[s] : &TL_TABLE[EG_ENT]; |
655 |
SIN_TABLE[SIN_ENT*2+s] = SIN_TABLE[s % (SIN_ENT/2)]; |
656 |
SIN_TABLE[SIN_ENT*3+s] = (s/(SIN_ENT/4))&1 ? &TL_TABLE[EG_ENT] : SIN_TABLE[SIN_ENT*2+s]; |
657 |
} |
658 |
|
659 |
/* envelope counter -> envelope output table */
|
660 |
for (i=0; i<EG_ENT; i++) |
661 |
{ |
662 |
/* ATTACK curve */
|
663 |
pom = pow( ((double)(EG_ENT-1-i)/EG_ENT) , 8 ) * EG_ENT; |
664 |
/* if( pom >= EG_ENT ) pom = EG_ENT-1; */
|
665 |
ENV_CURVE[i] = (int)pom;
|
666 |
/* DECAY ,RELEASE curve */
|
667 |
ENV_CURVE[(EG_DST>>ENV_BITS)+i]= i; |
668 |
} |
669 |
/* off */
|
670 |
ENV_CURVE[EG_OFF>>ENV_BITS]= EG_ENT-1;
|
671 |
/* make LFO ams table */
|
672 |
for (i=0; i<AMS_ENT; i++) |
673 |
{ |
674 |
pom = (1.0+sin(2*PI*i/AMS_ENT))/2; /* sin */ |
675 |
AMS_TABLE[i] = (1.0/EG_STEP)*pom; /* 1dB */ |
676 |
AMS_TABLE[AMS_ENT+i] = (4.8/EG_STEP)*pom; /* 4.8dB */ |
677 |
} |
678 |
/* make LFO vibrate table */
|
679 |
for (i=0; i<VIB_ENT; i++) |
680 |
{ |
681 |
/* 100cent = 1seminote = 6% ?? */
|
682 |
pom = (double)VIB_RATE*0.06*sin(2*PI*i/VIB_ENT); /* +-100sect step */ |
683 |
VIB_TABLE[i] = VIB_RATE + (pom*0.07); /* +- 7cent */ |
684 |
VIB_TABLE[VIB_ENT+i] = VIB_RATE + (pom*0.14); /* +-14cent */ |
685 |
/* LOG(LOG_INF,("vib %d=%d\n",i,VIB_TABLE[VIB_ENT+i])); */
|
686 |
} |
687 |
return 1; |
688 |
} |
689 |
|
690 |
|
691 |
static void OPLCloseTable( void ) |
692 |
{ |
693 |
free(TL_TABLE); |
694 |
free(SIN_TABLE); |
695 |
free(AMS_TABLE); |
696 |
free(VIB_TABLE); |
697 |
} |
698 |
|
699 |
/* CSM Key Controll */
|
700 |
INLINE void CSMKeyControll(OPL_CH *CH)
|
701 |
{ |
702 |
OPL_SLOT *slot1 = &CH->SLOT[SLOT1]; |
703 |
OPL_SLOT *slot2 = &CH->SLOT[SLOT2]; |
704 |
/* all key off */
|
705 |
OPL_KEYOFF(slot1); |
706 |
OPL_KEYOFF(slot2); |
707 |
/* total level latch */
|
708 |
slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl); |
709 |
slot1->TLL = slot1->TL + (CH->ksl_base>>slot1->ksl); |
710 |
/* key on */
|
711 |
CH->op1_out[0] = CH->op1_out[1] = 0; |
712 |
OPL_KEYON(slot1); |
713 |
OPL_KEYON(slot2); |
714 |
} |
715 |
|
716 |
/* ---------- opl initialize ---------- */
|
717 |
static void OPL_initalize(FM_OPL *OPL) |
718 |
{ |
719 |
int fn;
|
720 |
|
721 |
/* frequency base */
|
722 |
OPL->freqbase = (OPL->rate) ? ((double)OPL->clock / OPL->rate) / 72 : 0; |
723 |
/* Timer base time */
|
724 |
OPL->TimerBase = 1.0/((double)OPL->clock / 72.0 ); |
725 |
/* make time tables */
|
726 |
init_timetables( OPL , OPL_ARRATE , OPL_DRRATE ); |
727 |
/* make fnumber -> increment counter table */
|
728 |
for( fn=0 ; fn < 1024 ; fn++ ) |
729 |
{ |
730 |
OPL->FN_TABLE[fn] = OPL->freqbase * fn * FREQ_RATE * (1<<7) / 2; |
731 |
} |
732 |
/* LFO freq.table */
|
733 |
OPL->amsIncr = OPL->rate ? (double)AMS_ENT*(1<<AMS_SHIFT) / OPL->rate * 3.7 * ((double)OPL->clock/3600000) : 0; |
734 |
OPL->vibIncr = OPL->rate ? (double)VIB_ENT*(1<<VIB_SHIFT) / OPL->rate * 6.4 * ((double)OPL->clock/3600000) : 0; |
735 |
} |
736 |
|
737 |
/* ---------- write a OPL registers ---------- */
|
738 |
static void OPLWriteReg(FM_OPL *OPL, int r, int v) |
739 |
{ |
740 |
OPL_CH *CH; |
741 |
int slot;
|
742 |
int block_fnum;
|
743 |
|
744 |
switch(r&0xe0) |
745 |
{ |
746 |
case 0x00: /* 00-1f:controll */ |
747 |
switch(r&0x1f) |
748 |
{ |
749 |
case 0x01: |
750 |
/* wave selector enable */
|
751 |
if(OPL->type&OPL_TYPE_WAVESEL)
|
752 |
{ |
753 |
OPL->wavesel = v&0x20;
|
754 |
if(!OPL->wavesel)
|
755 |
{ |
756 |
/* preset compatible mode */
|
757 |
int c;
|
758 |
for(c=0;c<OPL->max_ch;c++) |
759 |
{ |
760 |
OPL->P_CH[c].SLOT[SLOT1].wavetable = &SIN_TABLE[0];
|
761 |
OPL->P_CH[c].SLOT[SLOT2].wavetable = &SIN_TABLE[0];
|
762 |
} |
763 |
} |
764 |
} |
765 |
return;
|
766 |
case 0x02: /* Timer 1 */ |
767 |
OPL->T[0] = (256-v)*4; |
768 |
break;
|
769 |
case 0x03: /* Timer 2 */ |
770 |
OPL->T[1] = (256-v)*16; |
771 |
return;
|
772 |
case 0x04: /* IRQ clear / mask and Timer enable */ |
773 |
if(v&0x80) |
774 |
{ /* IRQ flag clear */
|
775 |
OPL_STATUS_RESET(OPL,0x7f);
|
776 |
} |
777 |
else
|
778 |
{ /* set IRQ mask ,timer enable*/
|
779 |
UINT8 st1 = v&1;
|
780 |
UINT8 st2 = (v>>1)&1; |
781 |
/* IRQRST,T1MSK,t2MSK,EOSMSK,BRMSK,x,ST2,ST1 */
|
782 |
OPL_STATUS_RESET(OPL,v&0x78);
|
783 |
OPL_STATUSMASK_SET(OPL,((~v)&0x78)|0x01); |
784 |
/* timer 2 */
|
785 |
if(OPL->st[1] != st2) |
786 |
{ |
787 |
double interval = st2 ? (double)OPL->T[1]*OPL->TimerBase : 0.0; |
788 |
OPL->st[1] = st2;
|
789 |
if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+1,interval); |
790 |
} |
791 |
/* timer 1 */
|
792 |
if(OPL->st[0] != st1) |
793 |
{ |
794 |
double interval = st1 ? (double)OPL->T[0]*OPL->TimerBase : 0.0; |
795 |
OPL->st[0] = st1;
|
796 |
if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+0,interval); |
797 |
} |
798 |
} |
799 |
return;
|
800 |
#if BUILD_Y8950
|
801 |
case 0x06: /* Key Board OUT */ |
802 |
if(OPL->type&OPL_TYPE_KEYBOARD)
|
803 |
{ |
804 |
if(OPL->keyboardhandler_w)
|
805 |
OPL->keyboardhandler_w(OPL->keyboard_param,v); |
806 |
else
|
807 |
LOG(LOG_WAR,("OPL:write unmapped KEYBOARD port\n"));
|
808 |
} |
809 |
return;
|
810 |
case 0x07: /* DELTA-T controll : START,REC,MEMDATA,REPT,SPOFF,x,x,RST */ |
811 |
if(OPL->type&OPL_TYPE_ADPCM)
|
812 |
YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
|
813 |
return;
|
814 |
case 0x08: /* MODE,DELTA-T : CSM,NOTESEL,x,x,smpl,da/ad,64k,rom */ |
815 |
OPL->mode = v; |
816 |
v&=0x1f; /* for DELTA-T unit */ |
817 |
case 0x09: /* START ADD */ |
818 |
case 0x0a: |
819 |
case 0x0b: /* STOP ADD */ |
820 |
case 0x0c: |
821 |
case 0x0d: /* PRESCALE */ |
822 |
case 0x0e: |
823 |
case 0x0f: /* ADPCM data */ |
824 |
case 0x10: /* DELTA-N */ |
825 |
case 0x11: /* DELTA-N */ |
826 |
case 0x12: /* EG-CTRL */ |
827 |
if(OPL->type&OPL_TYPE_ADPCM)
|
828 |
YM_DELTAT_ADPCM_Write(OPL->deltat,r-0x07,v);
|
829 |
return;
|
830 |
#if 0
|
831 |
case 0x15: /* DAC data */
|
832 |
case 0x16:
|
833 |
case 0x17: /* SHIFT */
|
834 |
return;
|
835 |
case 0x18: /* I/O CTRL (Direction) */
|
836 |
if(OPL->type&OPL_TYPE_IO)
|
837 |
OPL->portDirection = v&0x0f;
|
838 |
return;
|
839 |
case 0x19: /* I/O DATA */
|
840 |
if(OPL->type&OPL_TYPE_IO)
|
841 |
{
|
842 |
OPL->portLatch = v;
|
843 |
if(OPL->porthandler_w)
|
844 |
OPL->porthandler_w(OPL->port_param,v&OPL->portDirection);
|
845 |
}
|
846 |
return;
|
847 |
case 0x1a: /* PCM data */
|
848 |
return;
|
849 |
#endif
|
850 |
#endif
|
851 |
} |
852 |
break;
|
853 |
case 0x20: /* am,vib,ksr,eg type,mul */ |
854 |
slot = slot_array[r&0x1f];
|
855 |
if(slot == -1) return; |
856 |
set_mul(OPL,slot,v); |
857 |
return;
|
858 |
case 0x40: |
859 |
slot = slot_array[r&0x1f];
|
860 |
if(slot == -1) return; |
861 |
set_ksl_tl(OPL,slot,v); |
862 |
return;
|
863 |
case 0x60: |
864 |
slot = slot_array[r&0x1f];
|
865 |
if(slot == -1) return; |
866 |
set_ar_dr(OPL,slot,v); |
867 |
return;
|
868 |
case 0x80: |
869 |
slot = slot_array[r&0x1f];
|
870 |
if(slot == -1) return; |
871 |
set_sl_rr(OPL,slot,v); |
872 |
return;
|
873 |
case 0xa0: |
874 |
switch(r)
|
875 |
{ |
876 |
case 0xbd: |
877 |
/* amsep,vibdep,r,bd,sd,tom,tc,hh */
|
878 |
{ |
879 |
UINT8 rkey = OPL->rythm^v; |
880 |
OPL->ams_table = &AMS_TABLE[v&0x80 ? AMS_ENT : 0]; |
881 |
OPL->vib_table = &VIB_TABLE[v&0x40 ? VIB_ENT : 0]; |
882 |
OPL->rythm = v&0x3f;
|
883 |
if(OPL->rythm&0x20) |
884 |
{ |
885 |
#if 0
|
886 |
usrintf_showmessage("OPL Rythm mode select");
|
887 |
#endif
|
888 |
/* BD key on/off */
|
889 |
if(rkey&0x10) |
890 |
{ |
891 |
if(v&0x10) |
892 |
{ |
893 |
OPL->P_CH[6].op1_out[0] = OPL->P_CH[6].op1_out[1] = 0; |
894 |
OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT1]);
|
895 |
OPL_KEYON(&OPL->P_CH[6].SLOT[SLOT2]);
|
896 |
} |
897 |
else
|
898 |
{ |
899 |
OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT1]);
|
900 |
OPL_KEYOFF(&OPL->P_CH[6].SLOT[SLOT2]);
|
901 |
} |
902 |
} |
903 |
/* SD key on/off */
|
904 |
if(rkey&0x08) |
905 |
{ |
906 |
if(v&0x08) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT2]); |
907 |
else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT2]); |
908 |
}/* TAM key on/off */
|
909 |
if(rkey&0x04) |
910 |
{ |
911 |
if(v&0x04) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT1]); |
912 |
else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT1]); |
913 |
} |
914 |
/* TOP-CY key on/off */
|
915 |
if(rkey&0x02) |
916 |
{ |
917 |
if(v&0x02) OPL_KEYON(&OPL->P_CH[8].SLOT[SLOT2]); |
918 |
else OPL_KEYOFF(&OPL->P_CH[8].SLOT[SLOT2]); |
919 |
} |
920 |
/* HH key on/off */
|
921 |
if(rkey&0x01) |
922 |
{ |
923 |
if(v&0x01) OPL_KEYON(&OPL->P_CH[7].SLOT[SLOT1]); |
924 |
else OPL_KEYOFF(&OPL->P_CH[7].SLOT[SLOT1]); |
925 |
} |
926 |
} |
927 |
} |
928 |
return;
|
929 |
} |
930 |
/* keyon,block,fnum */
|
931 |
if( (r&0x0f) > 8) return; |
932 |
CH = &OPL->P_CH[r&0x0f];
|
933 |
if(!(r&0x10)) |
934 |
{ /* a0-a8 */
|
935 |
block_fnum = (CH->block_fnum&0x1f00) | v;
|
936 |
} |
937 |
else
|
938 |
{ /* b0-b8 */
|
939 |
int keyon = (v>>5)&1; |
940 |
block_fnum = ((v&0x1f)<<8) | (CH->block_fnum&0xff); |
941 |
if(CH->keyon != keyon)
|
942 |
{ |
943 |
if( (CH->keyon=keyon) )
|
944 |
{ |
945 |
CH->op1_out[0] = CH->op1_out[1] = 0; |
946 |
OPL_KEYON(&CH->SLOT[SLOT1]); |
947 |
OPL_KEYON(&CH->SLOT[SLOT2]); |
948 |
} |
949 |
else
|
950 |
{ |
951 |
OPL_KEYOFF(&CH->SLOT[SLOT1]); |
952 |
OPL_KEYOFF(&CH->SLOT[SLOT2]); |
953 |
} |
954 |
} |
955 |
} |
956 |
/* update */
|
957 |
if(CH->block_fnum != block_fnum)
|
958 |
{ |
959 |
int blockRv = 7-(block_fnum>>10); |
960 |
int fnum = block_fnum&0x3ff; |
961 |
CH->block_fnum = block_fnum; |
962 |
|
963 |
CH->ksl_base = KSL_TABLE[block_fnum>>6];
|
964 |
CH->fc = OPL->FN_TABLE[fnum]>>blockRv; |
965 |
CH->kcode = CH->block_fnum>>9;
|
966 |
if( (OPL->mode&0x40) && CH->block_fnum&0x100) CH->kcode |=1; |
967 |
CALC_FCSLOT(CH,&CH->SLOT[SLOT1]); |
968 |
CALC_FCSLOT(CH,&CH->SLOT[SLOT2]); |
969 |
} |
970 |
return;
|
971 |
case 0xc0: |
972 |
/* FB,C */
|
973 |
if( (r&0x0f) > 8) return; |
974 |
CH = &OPL->P_CH[r&0x0f];
|
975 |
{ |
976 |
int feedback = (v>>1)&7; |
977 |
CH->FB = feedback ? (8+1) - feedback : 0; |
978 |
CH->CON = v&1;
|
979 |
set_algorythm(CH); |
980 |
} |
981 |
return;
|
982 |
case 0xe0: /* wave type */ |
983 |
slot = slot_array[r&0x1f];
|
984 |
if(slot == -1) return; |
985 |
CH = &OPL->P_CH[slot/2];
|
986 |
if(OPL->wavesel)
|
987 |
{ |
988 |
/* LOG(LOG_INF,("OPL SLOT %d wave select %d\n",slot,v&3)); */
|
989 |
CH->SLOT[slot&1].wavetable = &SIN_TABLE[(v&0x03)*SIN_ENT]; |
990 |
} |
991 |
return;
|
992 |
} |
993 |
} |
994 |
|
995 |
/* lock/unlock for common table */
|
996 |
static int OPL_LockTable(void) |
997 |
{ |
998 |
num_lock++; |
999 |
if(num_lock>1) return 0; |
1000 |
/* first time */
|
1001 |
cur_chip = NULL;
|
1002 |
/* allocate total level table (128kb space) */
|
1003 |
if( !OPLOpenTable() )
|
1004 |
{ |
1005 |
num_lock--; |
1006 |
return -1; |
1007 |
} |
1008 |
return 0; |
1009 |
} |
1010 |
|
1011 |
static void OPL_UnLockTable(void) |
1012 |
{ |
1013 |
if(num_lock) num_lock--;
|
1014 |
if(num_lock) return; |
1015 |
/* last time */
|
1016 |
cur_chip = NULL;
|
1017 |
OPLCloseTable(); |
1018 |
} |
1019 |
|
1020 |
#if (BUILD_YM3812 || BUILD_YM3526)
|
1021 |
/*******************************************************************************/
|
1022 |
/* YM3812 local section */
|
1023 |
/*******************************************************************************/
|
1024 |
|
1025 |
/* ---------- update one of chip ----------- */
|
1026 |
void YM3812UpdateOne(FM_OPL *OPL, INT16 *buffer, int length) |
1027 |
{ |
1028 |
int i;
|
1029 |
int data;
|
1030 |
OPLSAMPLE *buf = buffer; |
1031 |
UINT32 amsCnt = OPL->amsCnt; |
1032 |
UINT32 vibCnt = OPL->vibCnt; |
1033 |
UINT8 rythm = OPL->rythm&0x20;
|
1034 |
OPL_CH *CH,*R_CH; |
1035 |
|
1036 |
if( (void *)OPL != cur_chip ){ |
1037 |
cur_chip = (void *)OPL;
|
1038 |
/* channel pointers */
|
1039 |
S_CH = OPL->P_CH; |
1040 |
E_CH = &S_CH[9];
|
1041 |
/* rythm slot */
|
1042 |
SLOT7_1 = &S_CH[7].SLOT[SLOT1];
|
1043 |
SLOT7_2 = &S_CH[7].SLOT[SLOT2];
|
1044 |
SLOT8_1 = &S_CH[8].SLOT[SLOT1];
|
1045 |
SLOT8_2 = &S_CH[8].SLOT[SLOT2];
|
1046 |
/* LFO state */
|
1047 |
amsIncr = OPL->amsIncr; |
1048 |
vibIncr = OPL->vibIncr; |
1049 |
ams_table = OPL->ams_table; |
1050 |
vib_table = OPL->vib_table; |
1051 |
} |
1052 |
R_CH = rythm ? &S_CH[6] : E_CH;
|
1053 |
for( i=0; i < length ; i++ ) |
1054 |
{ |
1055 |
/* channel A channel B channel C */
|
1056 |
/* LFO */
|
1057 |
ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT]; |
1058 |
vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT]; |
1059 |
outd[0] = 0; |
1060 |
/* FM part */
|
1061 |
for(CH=S_CH ; CH < R_CH ; CH++)
|
1062 |
OPL_CALC_CH(CH); |
1063 |
/* Rythn part */
|
1064 |
if(rythm)
|
1065 |
OPL_CALC_RH(S_CH); |
1066 |
/* limit check */
|
1067 |
data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
|
1068 |
/* store to sound buffer */
|
1069 |
buf[i] = data >> OPL_OUTSB; |
1070 |
} |
1071 |
|
1072 |
OPL->amsCnt = amsCnt; |
1073 |
OPL->vibCnt = vibCnt; |
1074 |
#ifdef OPL_OUTPUT_LOG
|
1075 |
if(opl_dbg_fp)
|
1076 |
{ |
1077 |
for(opl_dbg_chip=0;opl_dbg_chip<opl_dbg_maxchip;opl_dbg_chip++) |
1078 |
if( opl_dbg_opl[opl_dbg_chip] == OPL) break; |
1079 |
fprintf(opl_dbg_fp,"%c%c%c",0x20+opl_dbg_chip,length&0xff,length/256); |
1080 |
} |
1081 |
#endif
|
1082 |
} |
1083 |
#endif /* (BUILD_YM3812 || BUILD_YM3526) */ |
1084 |
|
1085 |
#if BUILD_Y8950
|
1086 |
|
1087 |
void Y8950UpdateOne(FM_OPL *OPL, INT16 *buffer, int length) |
1088 |
{ |
1089 |
int i;
|
1090 |
int data;
|
1091 |
OPLSAMPLE *buf = buffer; |
1092 |
UINT32 amsCnt = OPL->amsCnt; |
1093 |
UINT32 vibCnt = OPL->vibCnt; |
1094 |
UINT8 rythm = OPL->rythm&0x20;
|
1095 |
OPL_CH *CH,*R_CH; |
1096 |
YM_DELTAT *DELTAT = OPL->deltat; |
1097 |
|
1098 |
/* setup DELTA-T unit */
|
1099 |
YM_DELTAT_DECODE_PRESET(DELTAT); |
1100 |
|
1101 |
if( (void *)OPL != cur_chip ){ |
1102 |
cur_chip = (void *)OPL;
|
1103 |
/* channel pointers */
|
1104 |
S_CH = OPL->P_CH; |
1105 |
E_CH = &S_CH[9];
|
1106 |
/* rythm slot */
|
1107 |
SLOT7_1 = &S_CH[7].SLOT[SLOT1];
|
1108 |
SLOT7_2 = &S_CH[7].SLOT[SLOT2];
|
1109 |
SLOT8_1 = &S_CH[8].SLOT[SLOT1];
|
1110 |
SLOT8_2 = &S_CH[8].SLOT[SLOT2];
|
1111 |
/* LFO state */
|
1112 |
amsIncr = OPL->amsIncr; |
1113 |
vibIncr = OPL->vibIncr; |
1114 |
ams_table = OPL->ams_table; |
1115 |
vib_table = OPL->vib_table; |
1116 |
} |
1117 |
R_CH = rythm ? &S_CH[6] : E_CH;
|
1118 |
for( i=0; i < length ; i++ ) |
1119 |
{ |
1120 |
/* channel A channel B channel C */
|
1121 |
/* LFO */
|
1122 |
ams = ams_table[(amsCnt+=amsIncr)>>AMS_SHIFT]; |
1123 |
vib = vib_table[(vibCnt+=vibIncr)>>VIB_SHIFT]; |
1124 |
outd[0] = 0; |
1125 |
/* deltaT ADPCM */
|
1126 |
if( DELTAT->portstate )
|
1127 |
YM_DELTAT_ADPCM_CALC(DELTAT); |
1128 |
/* FM part */
|
1129 |
for(CH=S_CH ; CH < R_CH ; CH++)
|
1130 |
OPL_CALC_CH(CH); |
1131 |
/* Rythn part */
|
1132 |
if(rythm)
|
1133 |
OPL_CALC_RH(S_CH); |
1134 |
/* limit check */
|
1135 |
data = Limit( outd[0] , OPL_MAXOUT, OPL_MINOUT );
|
1136 |
/* store to sound buffer */
|
1137 |
buf[i] = data >> OPL_OUTSB; |
1138 |
} |
1139 |
OPL->amsCnt = amsCnt; |
1140 |
OPL->vibCnt = vibCnt; |
1141 |
/* deltaT START flag */
|
1142 |
if( !DELTAT->portstate )
|
1143 |
OPL->status &= 0xfe;
|
1144 |
} |
1145 |
#endif
|
1146 |
|
1147 |
/* ---------- reset one of chip ---------- */
|
1148 |
void OPLResetChip(FM_OPL *OPL)
|
1149 |
{ |
1150 |
int c,s;
|
1151 |
int i;
|
1152 |
|
1153 |
/* reset chip */
|
1154 |
OPL->mode = 0; /* normal mode */ |
1155 |
OPL_STATUS_RESET(OPL,0x7f);
|
1156 |
/* reset with register write */
|
1157 |
OPLWriteReg(OPL,0x01,0); /* wabesel disable */ |
1158 |
OPLWriteReg(OPL,0x02,0); /* Timer1 */ |
1159 |
OPLWriteReg(OPL,0x03,0); /* Timer2 */ |
1160 |
OPLWriteReg(OPL,0x04,0); /* IRQ mask clear */ |
1161 |
for(i = 0xff ; i >= 0x20 ; i-- ) OPLWriteReg(OPL,i,0); |
1162 |
/* reset OPerator paramater */
|
1163 |
for( c = 0 ; c < OPL->max_ch ; c++ ) |
1164 |
{ |
1165 |
OPL_CH *CH = &OPL->P_CH[c]; |
1166 |
/* OPL->P_CH[c].PAN = OPN_CENTER; */
|
1167 |
for(s = 0 ; s < 2 ; s++ ) |
1168 |
{ |
1169 |
/* wave table */
|
1170 |
CH->SLOT[s].wavetable = &SIN_TABLE[0];
|
1171 |
/* CH->SLOT[s].evm = ENV_MOD_RR; */
|
1172 |
CH->SLOT[s].evc = EG_OFF; |
1173 |
CH->SLOT[s].eve = EG_OFF+1;
|
1174 |
CH->SLOT[s].evs = 0;
|
1175 |
} |
1176 |
} |
1177 |
#if BUILD_Y8950
|
1178 |
if(OPL->type&OPL_TYPE_ADPCM)
|
1179 |
{ |
1180 |
YM_DELTAT *DELTAT = OPL->deltat; |
1181 |
|
1182 |
DELTAT->freqbase = OPL->freqbase; |
1183 |
DELTAT->output_pointer = outd; |
1184 |
DELTAT->portshift = 5;
|
1185 |
DELTAT->output_range = DELTAT_MIXING_LEVEL<<TL_BITS; |
1186 |
YM_DELTAT_ADPCM_Reset(DELTAT,0);
|
1187 |
} |
1188 |
#endif
|
1189 |
} |
1190 |
|
1191 |
/* ---------- Create one of vietual YM3812 ---------- */
|
1192 |
/* 'rate' is sampling rate and 'bufsiz' is the size of the */
|
1193 |
FM_OPL *OPLCreate(int type, int clock, int rate) |
1194 |
{ |
1195 |
char *ptr;
|
1196 |
FM_OPL *OPL; |
1197 |
int state_size;
|
1198 |
int max_ch = 9; /* normaly 9 channels */ |
1199 |
|
1200 |
if( OPL_LockTable() ==-1) return NULL; |
1201 |
/* allocate OPL state space */
|
1202 |
state_size = sizeof(FM_OPL);
|
1203 |
state_size += sizeof(OPL_CH)*max_ch;
|
1204 |
#if BUILD_Y8950
|
1205 |
if(type&OPL_TYPE_ADPCM) state_size+= sizeof(YM_DELTAT); |
1206 |
#endif
|
1207 |
/* allocate memory block */
|
1208 |
ptr = qemu_malloc(state_size); |
1209 |
/* clear */
|
1210 |
memset(ptr,0,state_size);
|
1211 |
OPL = (FM_OPL *)ptr; ptr+=sizeof(FM_OPL);
|
1212 |
OPL->P_CH = (OPL_CH *)ptr; ptr+=sizeof(OPL_CH)*max_ch;
|
1213 |
#if BUILD_Y8950
|
1214 |
if(type&OPL_TYPE_ADPCM) OPL->deltat = (YM_DELTAT *)ptr; ptr+=sizeof(YM_DELTAT); |
1215 |
#endif
|
1216 |
/* set channel state pointer */
|
1217 |
OPL->type = type; |
1218 |
OPL->clock = clock; |
1219 |
OPL->rate = rate; |
1220 |
OPL->max_ch = max_ch; |
1221 |
/* init grobal tables */
|
1222 |
OPL_initalize(OPL); |
1223 |
/* reset chip */
|
1224 |
OPLResetChip(OPL); |
1225 |
#ifdef OPL_OUTPUT_LOG
|
1226 |
if(!opl_dbg_fp)
|
1227 |
{ |
1228 |
opl_dbg_fp = fopen("opllog.opl","wb"); |
1229 |
opl_dbg_maxchip = 0;
|
1230 |
} |
1231 |
if(opl_dbg_fp)
|
1232 |
{ |
1233 |
opl_dbg_opl[opl_dbg_maxchip] = OPL; |
1234 |
fprintf(opl_dbg_fp,"%c%c%c%c%c%c",0x00+opl_dbg_maxchip, |
1235 |
type, |
1236 |
clock&0xff,
|
1237 |
(clock/0x100)&0xff, |
1238 |
(clock/0x10000)&0xff, |
1239 |
(clock/0x1000000)&0xff); |
1240 |
opl_dbg_maxchip++; |
1241 |
} |
1242 |
#endif
|
1243 |
return OPL;
|
1244 |
} |
1245 |
|
1246 |
/* ---------- Destroy one of vietual YM3812 ---------- */
|
1247 |
void OPLDestroy(FM_OPL *OPL)
|
1248 |
{ |
1249 |
#ifdef OPL_OUTPUT_LOG
|
1250 |
if(opl_dbg_fp)
|
1251 |
{ |
1252 |
fclose(opl_dbg_fp); |
1253 |
opl_dbg_fp = NULL;
|
1254 |
} |
1255 |
#endif
|
1256 |
OPL_UnLockTable(); |
1257 |
free(OPL); |
1258 |
} |
1259 |
|
1260 |
/* ---------- Option handlers ---------- */
|
1261 |
|
1262 |
void OPLSetTimerHandler(FM_OPL *OPL,OPL_TIMERHANDLER TimerHandler,int channelOffset) |
1263 |
{ |
1264 |
OPL->TimerHandler = TimerHandler; |
1265 |
OPL->TimerParam = channelOffset; |
1266 |
} |
1267 |
void OPLSetIRQHandler(FM_OPL *OPL,OPL_IRQHANDLER IRQHandler,int param) |
1268 |
{ |
1269 |
OPL->IRQHandler = IRQHandler; |
1270 |
OPL->IRQParam = param; |
1271 |
} |
1272 |
void OPLSetUpdateHandler(FM_OPL *OPL,OPL_UPDATEHANDLER UpdateHandler,int param) |
1273 |
{ |
1274 |
OPL->UpdateHandler = UpdateHandler; |
1275 |
OPL->UpdateParam = param; |
1276 |
} |
1277 |
#if BUILD_Y8950
|
1278 |
void OPLSetPortHandler(FM_OPL *OPL,OPL_PORTHANDLER_W PortHandler_w,OPL_PORTHANDLER_R PortHandler_r,int param) |
1279 |
{ |
1280 |
OPL->porthandler_w = PortHandler_w; |
1281 |
OPL->porthandler_r = PortHandler_r; |
1282 |
OPL->port_param = param; |
1283 |
} |
1284 |
|
1285 |
void OPLSetKeyboardHandler(FM_OPL *OPL,OPL_PORTHANDLER_W KeyboardHandler_w,OPL_PORTHANDLER_R KeyboardHandler_r,int param) |
1286 |
{ |
1287 |
OPL->keyboardhandler_w = KeyboardHandler_w; |
1288 |
OPL->keyboardhandler_r = KeyboardHandler_r; |
1289 |
OPL->keyboard_param = param; |
1290 |
} |
1291 |
#endif
|
1292 |
/* ---------- YM3812 I/O interface ---------- */
|
1293 |
int OPLWrite(FM_OPL *OPL,int a,int v) |
1294 |
{ |
1295 |
if( !(a&1) ) |
1296 |
{ /* address port */
|
1297 |
OPL->address = v & 0xff;
|
1298 |
} |
1299 |
else
|
1300 |
{ /* data port */
|
1301 |
if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); |
1302 |
#ifdef OPL_OUTPUT_LOG
|
1303 |
if(opl_dbg_fp)
|
1304 |
{ |
1305 |
for(opl_dbg_chip=0;opl_dbg_chip<opl_dbg_maxchip;opl_dbg_chip++) |
1306 |
if( opl_dbg_opl[opl_dbg_chip] == OPL) break; |
1307 |
fprintf(opl_dbg_fp,"%c%c%c",0x10+opl_dbg_chip,OPL->address,v); |
1308 |
} |
1309 |
#endif
|
1310 |
OPLWriteReg(OPL,OPL->address,v); |
1311 |
} |
1312 |
return OPL->status>>7; |
1313 |
} |
1314 |
|
1315 |
unsigned char OPLRead(FM_OPL *OPL,int a) |
1316 |
{ |
1317 |
if( !(a&1) ) |
1318 |
{ /* status port */
|
1319 |
return OPL->status & (OPL->statusmask|0x80); |
1320 |
} |
1321 |
/* data port */
|
1322 |
switch(OPL->address)
|
1323 |
{ |
1324 |
case 0x05: /* KeyBoard IN */ |
1325 |
if(OPL->type&OPL_TYPE_KEYBOARD)
|
1326 |
{ |
1327 |
if(OPL->keyboardhandler_r)
|
1328 |
return OPL->keyboardhandler_r(OPL->keyboard_param);
|
1329 |
else
|
1330 |
LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n"));
|
1331 |
} |
1332 |
return 0; |
1333 |
#if 0
|
1334 |
case 0x0f: /* ADPCM-DATA */
|
1335 |
return 0;
|
1336 |
#endif
|
1337 |
case 0x19: /* I/O DATA */ |
1338 |
if(OPL->type&OPL_TYPE_IO)
|
1339 |
{ |
1340 |
if(OPL->porthandler_r)
|
1341 |
return OPL->porthandler_r(OPL->port_param);
|
1342 |
else
|
1343 |
LOG(LOG_WAR,("OPL:read unmapped I/O port\n"));
|
1344 |
} |
1345 |
return 0; |
1346 |
case 0x1a: /* PCM-DATA */ |
1347 |
return 0; |
1348 |
} |
1349 |
return 0; |
1350 |
} |
1351 |
|
1352 |
int OPLTimerOver(FM_OPL *OPL,int c) |
1353 |
{ |
1354 |
if( c )
|
1355 |
{ /* Timer B */
|
1356 |
OPL_STATUS_SET(OPL,0x20);
|
1357 |
} |
1358 |
else
|
1359 |
{ /* Timer A */
|
1360 |
OPL_STATUS_SET(OPL,0x40);
|
1361 |
/* CSM mode key,TL controll */
|
1362 |
if( OPL->mode & 0x80 ) |
1363 |
{ /* CSM mode total level latch and auto key on */
|
1364 |
int ch;
|
1365 |
if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); |
1366 |
for(ch=0;ch<9;ch++) |
1367 |
CSMKeyControll( &OPL->P_CH[ch] ); |
1368 |
} |
1369 |
} |
1370 |
/* reload timer */
|
1371 |
if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase); |
1372 |
return OPL->status>>7; |
1373 |
} |