Mercurial > audlegacy
annotate Plugins/Input/adplug/core/fmopl.c @ 920:999d1af32ab4 trunk
[svn] Extra_stereo effect plugin ported by deitarion. Some last pointer-related touchups by nemo & me.
author | chainsaw |
---|---|
date | Sat, 08 Apr 2006 19:44:43 -0700 |
parents | 0a73d1faeb4e |
children | c71e2ef2dcf4 |
rev | line source |
---|---|
359 | 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; | |
625
0a73d1faeb4e
[svn] GCC 4.1 warning fixes by Diego 'Flameeyes' Petteno from Gentoo.
chainsaw
parents:
359
diff
changeset
|
758 size_t block_fnum; |
359 | 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); | |
625
0a73d1faeb4e
[svn] GCC 4.1 warning fixes by Diego 'Flameeyes' Petteno from Gentoo.
chainsaw
parents:
359
diff
changeset
|
1346 else { |
359 | 1347 LOG(LOG_WAR,("OPL:read unmapped KEYBOARD port\n")); |
625
0a73d1faeb4e
[svn] GCC 4.1 warning fixes by Diego 'Flameeyes' Petteno from Gentoo.
chainsaw
parents:
359
diff
changeset
|
1348 return 0; /* Avoid warning about empty else clause */ |
0a73d1faeb4e
[svn] GCC 4.1 warning fixes by Diego 'Flameeyes' Petteno from Gentoo.
chainsaw
parents:
359
diff
changeset
|
1349 } |
359 | 1350 } |
1351 return 0; | |
1352 #if 0 | |
1353 case 0x0f: /* ADPCM-DATA */ | |
1354 return 0; | |
1355 #endif | |
1356 case 0x19: /* I/O DATA */ | |
1357 if(OPL->type&OPL_TYPE_IO) | |
1358 { | |
1359 if(OPL->porthandler_r) | |
1360 return OPL->porthandler_r(OPL->port_param); | |
625
0a73d1faeb4e
[svn] GCC 4.1 warning fixes by Diego 'Flameeyes' Petteno from Gentoo.
chainsaw
parents:
359
diff
changeset
|
1361 else { |
359 | 1362 LOG(LOG_WAR,("OPL:read unmapped I/O port\n")); |
625
0a73d1faeb4e
[svn] GCC 4.1 warning fixes by Diego 'Flameeyes' Petteno from Gentoo.
chainsaw
parents:
359
diff
changeset
|
1363 return 0; /* Avoid warning about empty else clause */ |
0a73d1faeb4e
[svn] GCC 4.1 warning fixes by Diego 'Flameeyes' Petteno from Gentoo.
chainsaw
parents:
359
diff
changeset
|
1364 } |
359 | 1365 } |
1366 return 0; | |
1367 case 0x1a: /* PCM-DATA */ | |
1368 return 0; | |
1369 } | |
1370 return 0; | |
1371 } | |
1372 | |
1373 int OPLTimerOver(FM_OPL *OPL,int c) | |
1374 { | |
1375 if( c ) | |
1376 { /* Timer B */ | |
1377 OPL_STATUS_SET(OPL,0x20); | |
1378 } | |
1379 else | |
1380 { /* Timer A */ | |
1381 OPL_STATUS_SET(OPL,0x40); | |
1382 /* CSM mode key,TL controll */ | |
1383 if( OPL->mode & 0x80 ) | |
1384 { /* CSM mode total level latch and auto key on */ | |
1385 int ch; | |
1386 if(OPL->UpdateHandler) OPL->UpdateHandler(OPL->UpdateParam,0); | |
1387 for(ch=0;ch<9;ch++) | |
1388 CSMKeyControll( &OPL->P_CH[ch] ); | |
1389 } | |
1390 } | |
1391 /* reload timer */ | |
1392 if (OPL->TimerHandler) (OPL->TimerHandler)(OPL->TimerParam+c,(double)OPL->T[c]*OPL->TimerBase); | |
1393 return OPL->status>>7; | |
1394 } |