summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/libgme/emu8950.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/libgme/emu8950.c')
-rw-r--r--lib/rbcodec/codecs/libgme/emu8950.c1206
1 files changed, 1206 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libgme/emu8950.c b/lib/rbcodec/codecs/libgme/emu8950.c
new file mode 100644
index 0000000000..2f8a32044f
--- /dev/null
+++ b/lib/rbcodec/codecs/libgme/emu8950.c
@@ -0,0 +1,1206 @@
1/*
2 * This file is based on:
3 * Y8950.cc -- Y8950 emulator from the openMSX team
4 * ported to c by gama
5 *
6 * The openMSX version is based on:
7 * emu8950.c -- Y8950 emulator written by Mitsutaka Okazaki 2001
8 * heavily rewritten to fit openMSX structure
9 */
10
11#include <math.h>
12#include "emu8950.h"
13
14#ifdef _MSC_VER
15#pragma warning( disable : 4355 )
16#endif
17
18#if !defined(ROCKBOX)
19 #define EMU8950_CALCUL_TABLES
20#else
21 #include "opltables.h"
22#endif
23
24// dB to Liner table
25static short dB2LinTab[(2*DB_MUTE)*2];
26// Dynamic range
27static unsigned int dphaseNoiseTable[1024][8];
28// LFO Table
29int pmtable[2][PM_PG_WIDTH];
30int amtable[2][AM_PG_WIDTH];
31
32/** WaveTable for each envelope amp. */
33static int sintable[PG_WIDTH];
34 /** Phase incr table for Attack. */
35static unsigned int dphaseARTable[16][16];
36/** Phase incr table for Decay and Release. */
37static unsigned int dphaseDRTable[16][16];
38/** KSL + TL Table. */
39#if !defined(ROCKBOX)
40static unsigned char tllTable[16][8][1<<TL_BITS][4];
41#else
42/* Use the table calculated in emu2413 which is identical. */
43extern unsigned char tllTable[16][8][1<<TL_BITS][4];
44#endif
45static int rksTable[2][8][2];
46/** Since we wont change clock rate in rockbox we can
47 skip this table */
48#if !defined(ROCKBOX)
49/** Phase incr table for PG. */
50static unsigned int dphaseTable[1024][8][16];
51#endif
52
53/** Liner to Log curve conversion table (for Attack rate). */
54static int AR_ADJUST_TABLE[1<<EG_BITS];
55
56//**************************************************//
57// //
58// Helper functions //
59// //
60//**************************************************//
61
62#define ALIGN(d, SS, SD) (d*(int)(SS/SD))
63
64inline static int DB_POS(int x)
65{
66 return (int)(x/DB_STEP);
67}
68
69inline static int DB_NEG(int x)
70{
71 return (int)(2*DB_MUTE+x/DB_STEP);
72}
73
74// Cut the lower b bits off
75inline static int HIGHBITS(int c, int b)
76{
77 return c >> b;
78}
79// Leave the lower b bits
80inline static int LOWBITS(int c, int b)
81{
82 return c & ((1<<b)-1);
83}
84// Expand x which is s bits to d bits
85inline static int EXPAND_BITS(int x, int s, int d)
86{
87 return x << (d-s);
88}
89
90//**************************************************//
91// //
92// Create tables //
93// //
94//**************************************************//
95
96// Table for AR to LogCurve.
97static void makeAdjustTable(void)
98{
99 AR_ADJUST_TABLE[0] = 1 << EG_BITS;
100 for (int i = 1; i < (1 << EG_BITS); i++)
101 #ifdef EMU8950_CALCUL_TABLES
102 AR_ADJUST_TABLE[i] = (int)((double)(1 << EG_BITS) - 1 -
103 (1 << EG_BITS) * log((double)i) / log((double)(1 << EG_BITS))) >> 1;
104 #else
105 AR_ADJUST_TABLE[i] = ar_adjust_coeff[i-1];
106 #endif
107}
108
109// Table for dB(0 -- (1<<DB_BITS)) to Liner(0 -- DB2LIN_AMP_WIDTH)
110static void makeDB2LinTable(void)
111{
112 int i;
113 for (i=0; i < 2*DB_MUTE; i++) {
114 dB2LinTab[i] = (i<DB_MUTE) ?
115 #ifdef EMU8950_CALCUL_TABLES
116 (int)((double)((1<<DB2LIN_AMP_BITS)-1)*pow((double)10,-(double)i*DB_STEP/20)) :
117 #else
118 db2lin_coeff[i] :
119 #endif
120 0;
121 dB2LinTab[i + 2*DB_MUTE] = -dB2LinTab[i];
122 }
123}
124
125// Sin Table
126static void makeSinTable(void)
127{
128 int i;
129 for (i=0; i < PG_WIDTH/4; i++)
130 #ifdef EMU8950_CALCUL_TABLES
131 sintable[i] = lin2db(sin(2.0*MPI*i/PG_WIDTH));
132 #else
133 sintable[i] = sin_coeff[i];
134 #endif
135 for (int i=0; i < PG_WIDTH/4; i++)
136 sintable[PG_WIDTH/2 - 1 - i] = sintable[i];
137 for (int i=0; i < PG_WIDTH/2; i++)
138 sintable[PG_WIDTH/2 + i] = 2*DB_MUTE + sintable[i];
139}
140
141static void makeDphaseNoiseTable(int sampleRate, int clockRate)
142{
143 for (int i=0; i<1024; i++)
144 for (int j=0; j<8; j++)
145 dphaseNoiseTable[i][j] = rate_adjust(i<<j, sampleRate, clockRate);
146}
147
148// Table for Pitch Modulator
149static void makePmTable(void)
150{
151 int i;
152 for (i=0; i < PM_PG_WIDTH; i++)
153 #ifdef EMU8950_CALCUL_TABLES
154 pmtable[0][i] = (int)((double)PM_AMP * pow(2.,(double)PM_DEPTH*sin(2.0*MPI*i/PM_PG_WIDTH)/1200));
155 #else
156 pmtable[0][i] = pm0_coeff[i];
157 #endif
158 for (i=0; i < PM_PG_WIDTH; i++)
159 #ifdef EMU8950_CALCUL_TABLES
160 pmtable[1][i] = (int)((double)PM_AMP * pow(2.,(double)PM_DEPTH2*sin(2.0*MPI*i/PM_PG_WIDTH)/1200));
161 #else
162 pmtable[1][i] = pm1_coeff[i];
163 #endif
164}
165
166// Table for Amp Modulator
167static void makeAmTable(void)
168{
169 int i;
170 for (i=0; i<AM_PG_WIDTH; i++)
171 #ifdef EMU8950_CALCUL_TABLES
172 amtable[0][i] = (int)((double)AM_DEPTH/2/DB_STEP * (1.0 + sin(2.0*MPI*i/PM_PG_WIDTH)));
173 #else
174 amtable[0][i] = am0_coeff[i];
175 #endif
176 for (i=0; i<AM_PG_WIDTH; i++)
177 #ifdef EMU8950_CALCUL_TABLES
178 amtable[1][i] = (int)((double)AM_DEPTH2/2/DB_STEP * (1.0 + sin(2.0*MPI*i/PM_PG_WIDTH)));
179 #else
180 amtable[1][i] = am1_coeff[i];
181 #endif
182}
183
184#if !defined(ROCKBOX)
185// Phase increment counter table
186static void makeDphaseTable(int sampleRate, int clockRate)
187{
188 int mltable[16] = {
189 1,1*2,2*2,3*2,4*2,5*2,6*2,7*2,8*2,9*2,10*2,10*2,12*2,12*2,15*2,15*2
190 };
191
192 int fnum, block, ML;
193 for (fnum=0; fnum<1024; fnum++)
194 for (block=0; block<8; block++)
195 for (ML=0; ML<16; ML++)
196 dphaseTable[fnum][block][ML] =
197 rate_adjust((((fnum * mltable[ML]) << block) >> (21 - DP_BITS)), sampleRate, clockRate);
198}
199#endif
200
201#if !defined(ROCKBOX)
202static void makeTllTable(void)
203{
204 #define dB2(x) (int)((x)*2)
205 static int kltable[16] = {
206 dB2( 0.000),dB2( 9.000),dB2(12.000),dB2(13.875),
207 dB2(15.000),dB2(16.125),dB2(16.875),dB2(17.625),
208 dB2(18.000),dB2(18.750),dB2(19.125),dB2(19.500),
209 dB2(19.875),dB2(20.250),dB2(20.625),dB2(21.000)
210 };
211
212 int fnum, block, TL, KL;
213 for (fnum=0; fnum<16; fnum++)
214 for (block=0; block<8; block++)
215 for (TL=0; TL<64; TL++)
216 for (KL=0; KL<4; KL++) {
217 if (KL==0) {
218 tllTable[fnum][block][TL][KL] = (ALIGN(TL, TL_STEP, EG_STEP) ) >> 1;
219 } else {
220 int tmp = kltable[fnum] - dB2(3.000) * (7 - block);
221 if (tmp <= 0)
222 tllTable[fnum][block][TL][KL] = (ALIGN(TL, TL_STEP, EG_STEP) ) >> 1;
223 else
224 tllTable[fnum][block][TL][KL] = ((int)((tmp>>(3-KL))/EG_STEP) + ALIGN(TL, TL_STEP, EG_STEP) ) >> 1;
225 }
226 }
227}
228#endif
229
230// Rate Table for Attack
231static void makeDphaseARTable(int sampleRate, int clockRate)
232{
233 int AR, Rks;
234 for (AR=0; AR<16; AR++)
235 for (Rks=0; Rks<16; Rks++) {
236 int RM = AR + (Rks>>2);
237 int RL = Rks&3;
238 if (RM>15) RM=15;
239 switch (AR) {
240 case 0:
241 dphaseARTable[AR][Rks] = 0;
242 break;
243 case 15:
244 dphaseARTable[AR][Rks] = EG_DP_WIDTH;
245 break;
246 default:
247 dphaseARTable[AR][Rks] = rate_adjust((3*(RL+4) << (RM+1)), sampleRate, clockRate);
248 break;
249 }
250 }
251}
252
253// Rate Table for Decay
254static void makeDphaseDRTable(int sampleRate, int clockRate)
255{
256 int DR, Rks;
257 for (DR=0; DR<16; DR++)
258 for (Rks=0; Rks<16; Rks++) {
259 int RM = DR + (Rks>>2);
260 int RL = Rks&3;
261 if (RM>15) RM=15;
262 switch (DR) {
263 case 0:
264 dphaseDRTable[DR][Rks] = 0;
265 break;
266 default:
267 dphaseDRTable[DR][Rks] = rate_adjust((RL+4) << (RM-1), sampleRate, clockRate);
268 break;
269 }
270 }
271}
272
273static void makeRksTable(void)
274{
275 int fnum9, block, KR;
276 for (fnum9=0; fnum9<2; fnum9++)
277 for (block=0; block<8; block++)
278 for (KR=0; KR<2; KR++) {
279 rksTable[fnum9][block][KR] = (KR != 0) ?
280 (block<<1) + fnum9:
281 block>>1;
282 }
283}
284
285//**********************************************************//
286// //
287// Patch //
288// //
289//**********************************************************//
290
291
292void patchReset(struct Patch* patch)
293{
294 patch->AM = patch->PM = patch->EG = false;
295 patch->KR = patch->ML = patch->KL = patch->TL =
296 patch->FB = patch->AR = patch->DR = patch->SL = patch->RR = 0;
297}
298
299
300//**********************************************************//
301// //
302// Slot //
303// //
304//**********************************************************//
305
306
307static inline void slotUpdatePG(struct Slot* slot)
308{
309#if defined(ROCKBOX)
310 static const int mltable[16] = {
311 1,1*2,2*2,3*2,4*2,5*2,6*2,7*2,8*2,9*2,10*2,10*2,12*2,12*2,15*2,15*2
312 };
313
314 slot->dphase = ((slot->fnum * mltable[slot->patch.ML]) << slot->block) >> (21 - DP_BITS);
315#else
316 slot->dphase = dphaseTable[slot->fnum][slot->block][slot->patch.ML];
317#endif
318}
319
320static inline void slotUpdateTLL(struct Slot* slot)
321{
322 slot->tll = (int)(tllTable[slot->fnum>>6][slot->block][slot->patch.TL][slot->patch.KL]) << 1;
323}
324
325static inline void slotUpdateRKS(struct Slot* slot)
326{
327 slot->rks = rksTable[slot->fnum>>9][slot->block][slot->patch.KR];
328}
329
330static inline void slotUpdateEG(struct Slot* slot)
331{
332 switch (slot->eg_mode) {
333 case ATTACK:
334 slot->eg_dphase = dphaseARTable[slot->patch.AR][slot->rks];
335 break;
336 case DECAY:
337 slot->eg_dphase = dphaseDRTable[slot->patch.DR][slot->rks];
338 break;
339 case SUSTINE:
340 slot->eg_dphase = dphaseDRTable[slot->patch.RR][slot->rks];
341 break;
342 case RELEASE:
343 slot->eg_dphase = slot->patch.EG ?
344 dphaseDRTable[slot->patch.RR][slot->rks]:
345 dphaseDRTable[7] [slot->rks];
346 break;
347 case SUSHOLD:
348 case FINISH:
349 slot->eg_dphase = 0;
350 break;
351 }
352}
353
354static inline void slotUpdateAll(struct Slot* slot)
355{
356 slotUpdatePG(slot);
357 slotUpdateTLL(slot);
358 slotUpdateRKS(slot);
359 slotUpdateEG(slot); // EG should be last
360}
361
362void slotReset(struct Slot* slot)
363{
364 slot->phase = 0;
365 slot->dphase = 0;
366 slot->output[0] = 0;
367 slot->output[1] = 0;
368 slot->feedback = 0;
369 slot->eg_mode = FINISH;
370 slot->eg_phase = EG_DP_WIDTH;
371 slot->eg_dphase = 0;
372 slot->rks = 0;
373 slot->tll = 0;
374 slot->fnum = 0;
375 slot->block = 0;
376 slot->pgout = 0;
377 slot->egout = 0;
378 slot->slotStatus = false;
379 patchReset(&slot->patch);
380 slotUpdateAll(slot);
381}
382
383// Slot key on
384static inline void slotOn(struct Slot* slot)
385{
386 if (!slot->slotStatus) {
387 slot->slotStatus = true;
388 slot->eg_mode = ATTACK;
389 slot->phase = 0;
390 slot->eg_phase = 0;
391 }
392}
393
394// Slot key off
395static inline void slotOff(struct Slot* slot)
396{
397 if (slot->slotStatus) {
398 slot->slotStatus = false;
399 if (slot->eg_mode == ATTACK)
400 slot->eg_phase = EXPAND_BITS(AR_ADJUST_TABLE[HIGHBITS(slot->eg_phase, EG_DP_BITS-EG_BITS)], EG_BITS, EG_DP_BITS);
401 slot->eg_mode = RELEASE;
402 }
403}
404
405
406//**********************************************************//
407// //
408// OPLChannel //
409// //
410//**********************************************************//
411
412
413void channelReset(struct OPLChannel* ch)
414{
415 slotReset(&ch->mod);
416 slotReset(&ch->car);
417 ch->alg = false;
418}
419
420// Set F-Number ( fnum : 10bit )
421static void channelSetFnumber(struct OPLChannel* ch, int fnum)
422{
423 ch->car.fnum = fnum;
424 ch->mod.fnum = fnum;
425}
426
427// Set Block data (block : 3bit )
428static void channelSetBlock(struct OPLChannel* ch, int block)
429{
430 ch->car.block = block;
431 ch->mod.block = block;
432}
433
434// OPLChannel key on
435static void keyOn(struct OPLChannel* ch)
436{
437 slotOn(&ch->mod);
438 slotOn(&ch->car);
439}
440
441// OPLChannel key off
442static void keyOff(struct OPLChannel* ch)
443{
444 slotOff(&ch->mod);
445 slotOff(&ch->car);
446}
447
448
449//**********************************************************//
450// //
451// Y8950 //
452// //
453//**********************************************************//
454
455void OPL_init(struct Y8950* this, byte* ramBank, int sampleRam)
456{
457 this->clockRate = CLK_FREQ;
458
459 ADPCM_init(&this->adpcm, this, ramBank, sampleRam);
460
461 makePmTable();
462 makeAmTable();
463
464 makeAdjustTable();
465 makeDB2LinTable();
466#if !defined(ROCKBOX)
467 makeTllTable();
468#endif
469 makeRksTable();
470 makeSinTable();
471
472 int i;
473 for (i=0; i<9; i++) {
474 // TODO cleanup
475 this->slot[i*2+0] = &(this->ch[i].mod);
476 this->slot[i*2+1] = &(this->ch[i].car);
477 this->ch[i].mod.plfo_am = &this->lfo_am;
478 this->ch[i].mod.plfo_pm = &this->lfo_pm;
479 this->ch[i].car.plfo_am = &this->lfo_am;
480 this->ch[i].car.plfo_pm = &this->lfo_pm;
481 }
482
483 OPL_reset(this);
484}
485
486void OPL_setSampleRate(struct Y8950* this, int sampleRate, int clockRate)
487{
488 this->clockRate = clockRate;
489 ADPCM_setSampleRate(&this->adpcm, sampleRate, clockRate);
490
491#if !defined(ROCKBOX)
492 makeDphaseTable(sampleRate, clockRate);
493#endif
494 makeDphaseARTable(sampleRate, clockRate);
495 makeDphaseDRTable(sampleRate, clockRate);
496 makeDphaseNoiseTable(sampleRate, clockRate);
497 this->pm_dphase = rate_adjust( (int)(PM_SPEED * PM_DP_WIDTH) / (clockRate/72), sampleRate, clockRate);
498 this->am_dphase = rate_adjust( (int)(AM_SPEED * AM_DP_WIDTH) / (clockRate/72), sampleRate, clockRate);
499}
500
501// Reset whole of opl except patch datas.
502void OPL_reset(struct Y8950* this)
503{
504 int i;
505 for (i=0; i<9; i++)
506 channelReset(&this->ch[i]);
507 this->output[0] = 0;
508 this->output[1] = 0;
509
510
511 this->dacSampleVolume = 0;
512 this->dacOldSampleVolume = 0;
513 this->dacSampleVolumeSum = 0;
514 this->dacCtrlVolume = 0;
515 this->dacDaVolume = 0;
516 this->dacEnabled = 0;
517
518 this->rythm_mode = false;
519 this->am_mode = 0;
520 this->pm_mode = 0;
521 this->pm_phase = 0;
522 this->am_phase = 0;
523 this->noise_seed = 0xffff;
524 this->noiseA = 0;
525 this->noiseB = 0;
526 this->noiseA_phase = 0;
527 this->noiseB_phase = 0;
528 this->noiseA_dphase = 0;
529 this->noiseB_dphase = 0;
530
531 for (i = 0; i < 0x100; ++i)
532 this->reg[i] = 0x00;
533
534 this->reg[0x04] = 0x18;
535 this->reg[0x19] = 0x0F; // fixes 'Thunderbirds are Go'
536 this->status = 0x00;
537 this->statusMask = 0;
538 /* irq.reset(); */
539
540 ADPCM_reset(&this->adpcm);
541 OPL_setInternalMute(this, true); // muted
542}
543
544
545// Drum key on
546static inline void keyOn_BD(struct Y8950* this) { keyOn(&this->ch[6]); }
547static inline void keyOn_HH(struct Y8950* this) { slotOn(&this->ch[7].mod); }
548static inline void keyOn_SD(struct Y8950* this) { slotOn(&this->ch[7].car); }
549static inline void keyOn_TOM(struct Y8950* this) { slotOn(&this->ch[8].mod); }
550static inline void keyOn_CYM(struct Y8950* this) { slotOn(&this->ch[8].car); }
551
552// Drum key off
553static inline void keyOff_BD(struct Y8950* this) { keyOff(&this->ch[6]); }
554static inline void keyOff_HH(struct Y8950* this) { slotOff(&this->ch[7].mod); }
555static inline void keyOff_SD(struct Y8950* this) { slotOff(&this->ch[7].car); }
556static inline void keyOff_TOM(struct Y8950* this){ slotOff(&this->ch[8].mod); }
557static inline void keyOff_CYM(struct Y8950* this){ slotOff(&this->ch[8].car); }
558
559// Change Rhythm Mode
560static inline void setRythmMode(struct Y8950* this, int data)
561{
562 bool newMode = (data & 32) != 0;
563 if (this->rythm_mode != newMode) {
564 this->rythm_mode = newMode;
565 if (!this->rythm_mode) {
566 // ON->OFF
567 this->ch[6].mod.eg_mode = FINISH; // BD1
568 this->ch[6].mod.slotStatus = false;
569 this->ch[6].car.eg_mode = FINISH; // BD2
570 this->ch[6].car.slotStatus = false;
571 this->ch[7].mod.eg_mode = FINISH; // HH
572 this->ch[7].mod.slotStatus = false;
573 this->ch[7].car.eg_mode = FINISH; // SD
574 this->ch[7].car.slotStatus = false;
575 this->ch[8].mod.eg_mode = FINISH; // TOM
576 this->ch[8].mod.slotStatus = false;
577 this->ch[8].car.eg_mode = FINISH; // CYM
578 this->ch[8].car.slotStatus = false;
579 }
580 }
581}
582
583//********************************************************//
584// //
585// Generate wave data //
586// //
587//********************************************************//
588
589// Convert Amp(0 to EG_HEIGHT) to Phase(0 to 4PI).
590inline static int wave2_4pi(int e)
591{
592 int shift = SLOT_AMP_BITS - PG_BITS - 1;
593 if (shift > 0)
594 return e >> shift;
595 else
596 return e << -shift;
597}
598
599// Convert Amp(0 to EG_HEIGHT) to Phase(0 to 8PI).
600inline static int wave2_8pi(int e)
601{
602 int shift = SLOT_AMP_BITS - PG_BITS - 2;
603 if (shift > 0)
604 return e >> shift;
605 else
606 return e << -shift;
607}
608
609static inline void update_noise(struct Y8950* this)
610{
611 if (this->noise_seed & 1)
612 this->noise_seed ^= 0x24000;
613 this->noise_seed >>= 1;
614 this->whitenoise = this->noise_seed&1 ? DB_POS(6) : DB_NEG(6);
615
616 this->noiseA_phase += this->noiseA_dphase;
617 this->noiseB_phase += this->noiseB_dphase;
618
619 this->noiseA_phase &= (0x40<<11) - 1;
620 if ((this->noiseA_phase>>11)==0x3f)
621 this->noiseA_phase = 0;
622 this->noiseA = this->noiseA_phase&(0x03<<11)?DB_POS(6):DB_NEG(6);
623
624 this->noiseB_phase &= (0x10<<11) - 1;
625 this->noiseB = this->noiseB_phase&(0x0A<<11)?DB_POS(6):DB_NEG(6);
626}
627
628static inline void update_ampm(struct Y8950* this)
629{
630 this->pm_phase = (this->pm_phase + this->pm_dphase)&(PM_DP_WIDTH - 1);
631 this->am_phase = (this->am_phase + this->am_dphase)&(AM_DP_WIDTH - 1);
632 this->lfo_am = amtable[this->am_mode][HIGHBITS(this->am_phase, AM_DP_BITS - AM_PG_BITS)];
633 this->lfo_pm = pmtable[this->pm_mode][HIGHBITS(this->pm_phase, PM_DP_BITS - PM_PG_BITS)];
634}
635
636static inline void calc_phase(struct Slot* slot)
637{
638 if (slot->patch.PM)
639 slot->phase += (slot->dphase * (*slot->plfo_pm)) >> PM_AMP_BITS;
640 else
641 slot->phase += slot->dphase;
642 slot->phase &= (DP_WIDTH - 1);
643 slot->pgout = HIGHBITS(slot->phase, DP_BASE_BITS);
644}
645
646static inline void calc_envelope(struct Slot* slot)
647{
648 #define S2E(x) (ALIGN((unsigned int)(x/SL_STEP),SL_STEP,EG_STEP)<<(EG_DP_BITS-EG_BITS))
649 static unsigned int SL[16] = {
650 S2E( 0), S2E( 3), S2E( 6), S2E( 9), S2E(12), S2E(15), S2E(18), S2E(21),
651 S2E(24), S2E(27), S2E(30), S2E(33), S2E(36), S2E(39), S2E(42), S2E(93)
652 };
653
654 switch (slot->eg_mode) {
655 case ATTACK:
656 slot->eg_phase += slot->eg_dphase;
657 if (EG_DP_WIDTH & slot->eg_phase) {
658 slot->egout = 0;
659 slot->eg_phase= 0;
660 slot->eg_mode = DECAY;
661 slotUpdateEG(slot);
662 } else {
663 slot->egout = AR_ADJUST_TABLE[HIGHBITS(slot->eg_phase, EG_DP_BITS - EG_BITS)];
664 }
665 break;
666
667 case DECAY:
668 slot->eg_phase += slot->eg_dphase;
669 slot->egout = HIGHBITS(slot->eg_phase, EG_DP_BITS - EG_BITS);
670 if (slot->eg_phase >= SL[slot->patch.SL]) {
671 if (slot->patch.EG) {
672 slot->eg_phase = SL[slot->patch.SL];
673 slot->eg_mode = SUSHOLD;
674 slotUpdateEG(slot);
675 } else {
676 slot->eg_phase = SL[slot->patch.SL];
677 slot->eg_mode = SUSTINE;
678 slotUpdateEG(slot);
679 }
680 slot->egout = HIGHBITS(slot->eg_phase, EG_DP_BITS - EG_BITS);
681 }
682 break;
683
684 case SUSHOLD:
685 slot->egout = HIGHBITS(slot->eg_phase, EG_DP_BITS - EG_BITS);
686 if (!slot->patch.EG) {
687 slot->eg_mode = SUSTINE;
688 slotUpdateEG(slot);
689 }
690 break;
691
692 case SUSTINE:
693 case RELEASE:
694 slot->eg_phase += slot->eg_dphase;
695 slot->egout = HIGHBITS(slot->eg_phase, EG_DP_BITS - EG_BITS);
696 if (slot->egout >= (1<<EG_BITS)) {
697 slot->eg_mode = FINISH;
698 slot->egout = (1<<EG_BITS) - 1;
699 }
700 break;
701
702 case FINISH:
703 slot->egout = (1<<EG_BITS) - 1;
704 break;
705 }
706
707 if (slot->patch.AM)
708 slot->egout = ALIGN(slot->egout+slot->tll,EG_STEP,DB_STEP) + (*slot->plfo_am);
709 else
710 slot->egout = ALIGN(slot->egout+slot->tll,EG_STEP,DB_STEP);
711 if (slot->egout >= DB_MUTE)
712 slot->egout = DB_MUTE-1;
713}
714
715inline static int calc_slot_car(struct Slot* slot, int fm)
716{
717 calc_envelope(slot);
718 calc_phase(slot);
719 if (slot->egout>=(DB_MUTE-1))
720 return 0;
721 return dB2LinTab[sintable[(slot->pgout+wave2_8pi(fm))&(PG_WIDTH-1)] + slot->egout];
722}
723
724inline static int calc_slot_mod(struct Slot* slot)
725{
726 slot->output[1] = slot->output[0];
727 calc_envelope(slot);
728 calc_phase(slot);
729
730 if (slot->egout>=(DB_MUTE-1)) {
731 slot->output[0] = 0;
732 } else if (slot->patch.FB!=0) {
733 int fm = wave2_4pi(slot->feedback) >> (7-slot->patch.FB);
734 slot->output[0] = dB2LinTab[sintable[(slot->pgout+fm)&(PG_WIDTH-1)] + slot->egout];
735 } else
736 slot->output[0] = dB2LinTab[sintable[slot->pgout] + slot->egout];
737
738 slot->feedback = (slot->output[1] + slot->output[0])>>1;
739 return slot->feedback;
740}
741
742// TOM
743inline static int calc_slot_tom(struct Slot* slot)
744{
745 calc_envelope(slot);
746 calc_phase(slot);
747 if (slot->egout>=(DB_MUTE-1))
748 return 0;
749 return dB2LinTab[sintable[slot->pgout] + slot->egout];
750}
751
752// SNARE
753inline static int calc_slot_snare(struct Slot* slot, int whitenoise)
754{
755 calc_envelope(slot);
756 calc_phase(slot);
757 if (slot->egout>=(DB_MUTE-1))
758 return 0;
759 if (slot->pgout & (1<<(PG_BITS-1))) {
760 return (dB2LinTab[slot->egout] + dB2LinTab[slot->egout+whitenoise]) >> 1;
761 } else {
762 return (dB2LinTab[2*DB_MUTE + slot->egout] + dB2LinTab[slot->egout+whitenoise]) >> 1;
763 }
764}
765
766// TOP-CYM
767inline static int calc_slot_cym(struct Slot* slot, int a, int b)
768{
769 calc_envelope(slot);
770 if (slot->egout>=(DB_MUTE-1)) {
771 return 0;
772 } else {
773 return (dB2LinTab[slot->egout+a] + dB2LinTab[slot->egout+b]) >> 1;
774 }
775}
776
777// HI-HAT
778inline static int calc_slot_hat(struct Slot* slot, int a, int b, int whitenoise)
779{
780 calc_envelope(slot);
781 if (slot->egout>=(DB_MUTE-1)) {
782 return 0;
783 } else {
784 return (dB2LinTab[slot->egout+whitenoise] + dB2LinTab[slot->egout+a] + dB2LinTab[slot->egout+b]) >>2;
785 }
786}
787
788
789static inline int calcSample(struct Y8950* this, int channelMask)
790{
791 // while muted update_ampm() and update_noise() aren't called, probably ok
792 update_ampm(this);
793 update_noise(this);
794
795 int mix = 0;
796
797 if (this->rythm_mode) {
798 // TODO wasn't in original source either
799 calc_phase(&this->ch[7].mod);
800 calc_phase(&this->ch[8].car);
801
802 if (channelMask & (1 << 6))
803 mix += calc_slot_car(&this->ch[6].car, calc_slot_mod(&this->ch[6].mod));
804 if (this->ch[7].mod.eg_mode != FINISH)
805 mix += calc_slot_hat(&this->ch[7].mod, this->noiseA, this->noiseB, this->whitenoise);
806 if (channelMask & (1 << 7))
807 mix += calc_slot_snare(&this->ch[7].car, this->whitenoise);
808 if (this->ch[8].mod.eg_mode != FINISH)
809 mix += calc_slot_tom(&this->ch[8].mod);
810 if (channelMask & (1 << 8))
811 mix += calc_slot_cym(&this->ch[8].car, this->noiseA, this->noiseB);
812
813 channelMask &= (1<< 6) - 1;
814 mix *= 2;
815 }
816 struct OPLChannel *cp;
817 for (cp = this->ch; channelMask; channelMask >>=1, cp++) {
818 if (channelMask & 1) {
819 if (cp->alg)
820 mix += calc_slot_car(&cp->car, 0) +
821 calc_slot_mod(&cp->mod);
822 else
823 mix += calc_slot_car(&cp->car,
824 calc_slot_mod(&cp->mod));
825 }
826 }
827
828 mix += ADPCM_calcSample(&this->adpcm);
829
830 return (mix*this->maxVolume) >> (DB2LIN_AMP_BITS - 1);
831}
832
833static bool checkMuteHelper(struct Y8950* this)
834{
835 int i;
836 struct OPLChannel *ch = this->ch;
837 for (i = 0; i < 6; i++) {
838 if (ch[i].car.eg_mode != FINISH) return false;
839 }
840 if (!this->rythm_mode) {
841 for(i = 6; i < 9; i++) {
842 if (ch[i].car.eg_mode != FINISH) return false;
843 }
844 } else {
845 if (ch[6].car.eg_mode != FINISH) return false;
846 if (ch[7].mod.eg_mode != FINISH) return false;
847 if (ch[7].car.eg_mode != FINISH) return false;
848 if (ch[8].mod.eg_mode != FINISH) return false;
849 if (ch[8].car.eg_mode != FINISH) return false;
850 }
851
852 return ADPCM_muted(&this->adpcm);
853}
854
855static void checkMute(struct Y8950* this)
856{
857 bool mute = checkMuteHelper(this);
858 //PRT_DEBUG("Y8950: muted " << mute);
859 OPL_setInternalMute(this, mute);
860}
861
862int* OPL_updateBuffer(struct Y8950* this, int length)
863{
864 //PRT_DEBUG("Y8950: update buffer");
865
866 if (OPL_isInternalMuted(this) && !this->dacEnabled) {
867 return 0;
868 }
869
870 this->dacCtrlVolume = this->dacSampleVolume - this->dacOldSampleVolume + 0x3fe7 * this->dacCtrlVolume / 0x4000;
871 this->dacOldSampleVolume = this->dacSampleVolume;
872
873 int channelMask = 0, i;
874 struct OPLChannel *ch = this->ch;
875 for (i = 9; i--; ) {
876 channelMask <<= 1;
877 if (ch[i].car.eg_mode != FINISH) channelMask |= 1;
878 }
879
880 int* buf = this->buffer;
881 while (length--) {
882 int sample = calcSample(this, channelMask);
883
884 this->dacCtrlVolume = 0x3fe7 * this->dacCtrlVolume / 0x4000;
885 this->dacDaVolume += 2 * (this->dacCtrlVolume - this->dacDaVolume) / 3;
886 sample += 48 * this->dacDaVolume;
887 *(buf++) = sample;
888 }
889
890 this->dacEnabled = this->dacDaVolume;
891
892 checkMute(this);
893 return this->buffer;
894}
895
896void OPL_setInternalVolume(struct Y8950* this, short newVolume)
897{
898 this->maxVolume = newVolume;
899}
900
901//**************************************************//
902// //
903// I/O Ctrl //
904// //
905//**************************************************//
906
907void OPL_writeReg(struct Y8950* this, byte rg, byte data)
908{
909 //PRT_DEBUG("Y8950 write " << (int)rg << " " << (int)data);
910 int stbl[32] = {
911 0, 2, 4, 1, 3, 5,-1,-1,
912 6, 8,10, 7, 9,11,-1,-1,
913 12,14,16,13,15,17,-1,-1,
914 -1,-1,-1,-1,-1,-1,-1,-1
915 };
916
917 //TODO only for registers that influence sound
918 //TODO also ADPCM
919
920 switch (rg & 0xe0) {
921 case 0x00: {
922 switch (rg) {
923 case 0x01: // TEST
924 // TODO
925 // Y8950 MSX-AUDIO Test register $01 (write only)
926 //
927 // Bit Description
928 //
929 // 7 Reset LFOs - seems to force the LFOs to their initial values (eg.
930 // maximum amplitude, zero phase deviation)
931 //
932 // 6 something to do with ADPCM - bit 0 of the status register is
933 // affected by setting this bit (PCM BSY)
934 //
935 // 5 No effect? - Waveform select enable in YM3812 OPL2 so seems
936 // reasonable that this bit wouldn't have been used in OPL
937 //
938 // 4 No effect?
939 //
940 // 3 Faster LFOs - increases the frequencies of the LFOs and (maybe)
941 // the timers (cf. YM2151 test register)
942 //
943 // 2 Reset phase generators - No phase generator output, but envelope
944 // generators still work (can hear a transient when they are gated)
945 //
946 // 1 No effect?
947 //
948 // 0 Reset envelopes - Envelope generator outputs forced to maximum,
949 // so all enabled voices sound at maximum
950 this->reg[rg] = data;
951 break;
952
953 case 0x02: // TIMER1 (reso. 80us)
954 this->reg[rg] = data;
955 break;
956
957 case 0x03: // TIMER2 (reso. 320us)
958 this->reg[rg] = data;
959 break;
960
961 case 0x04: // FLAG CONTROL
962 if (data & R04_IRQ_RESET) {
963 OPL_resetStatus(this, 0x78); // reset all flags
964 } else {
965 OPL_changeStatusMask(this, (~data) & 0x78);
966 this->reg[rg] = data;
967 }
968 break;
969
970 case 0x06: // (KEYBOARD OUT)
971 this->reg[rg] = data;
972 break;
973
974 case 0x07: // START/REC/MEM DATA/REPEAT/SP-OFF/-/-/RESET
975 case 0x08: // CSM/KEY BOARD SPLIT/-/-/SAMPLE/DA AD/64K/ROM
976 case 0x09: // START ADDRESS (L)
977 case 0x0A: // START ADDRESS (H)
978 case 0x0B: // STOP ADDRESS (L)
979 case 0x0C: // STOP ADDRESS (H)
980 case 0x0D: // PRESCALE (L)
981 case 0x0E: // PRESCALE (H)
982 case 0x0F: // ADPCM-DATA
983 case 0x10: // DELTA-N (L)
984 case 0x11: // DELTA-N (H)
985 case 0x12: // ENVELOP CONTROL
986 case 0x1A: // PCM-DATA
987 this->reg[rg] = data;
988 ADPCM_writeReg(&this->adpcm, rg, data);
989 break;
990
991 case 0x15: // DAC-DATA (bit9-2)
992 this->reg[rg] = data;
993 if (this->reg[0x08] & 0x04) {
994 static int damp[] = { 256, 279, 304, 332, 362, 395, 431, 470 };
995 int sample = (short)(256 * this->reg[0x15] + this->reg[0x16]) * 128 / damp[this->reg[0x17]];
996 this->dacSampleVolume = sample;
997 this->dacEnabled = 1;
998 }
999 break;
1000 case 0x16: // (bit1-0)
1001 this->reg[rg] = data & 0xC0;
1002 break;
1003 case 0x17: // (exponent)
1004 this->reg[rg] = data & 0x07;
1005 break;
1006
1007 case 0x18: // I/O-CONTROL (bit3-0)
1008 // TODO
1009 // 0 -> input
1010 // 1 -> output
1011 this->reg[rg] = data;
1012 break;
1013
1014 case 0x19: // I/O-DATA (bit3-0)
1015 // TODO
1016 this->reg[rg] = data;
1017 break;
1018 }
1019
1020 break;
1021 }
1022 case 0x20: {
1023 int s = stbl[rg&0x1f];
1024 if (s >= 0) {
1025 this->slot[s]->patch.AM = (data>>7)&1;
1026 this->slot[s]->patch.PM = (data>>6)&1;
1027 this->slot[s]->patch.EG = (data>>5)&1;
1028 this->slot[s]->patch.KR = (data>>4)&1;
1029 this->slot[s]->patch.ML = (data)&15;
1030 slotUpdateAll(this->slot[s]);
1031 }
1032 this->reg[rg] = data;
1033 break;
1034 }
1035 case 0x40: {
1036 int s = stbl[rg&0x1f];
1037 if (s >= 0) {
1038 this->slot[s]->patch.KL = (data>>6)&3;
1039 this->slot[s]->patch.TL = (data)&63;
1040 slotUpdateAll(this->slot[s]);
1041 }
1042 this->reg[rg] = data;
1043 break;
1044 }
1045 case 0x60: {
1046 int s = stbl[rg&0x1f];
1047 if (s >= 0) {
1048 this->slot[s]->patch.AR = (data>>4)&15;
1049 this->slot[s]->patch.DR = (data)&15;
1050 slotUpdateEG(this->slot[s]);
1051 }
1052 this->reg[rg] = data;
1053 break;
1054 }
1055 case 0x80: {
1056 int s = stbl[rg&0x1f];
1057 if (s >= 0) {
1058 this->slot[s]->patch.SL = (data>>4)&15;
1059 this->slot[s]->patch.RR = (data)&15;
1060 slotUpdateEG(this->slot[s]);
1061 }
1062 this->reg[rg] = data;
1063 break;
1064 }
1065 case 0xa0: {
1066 if (rg==0xbd) {
1067 this->am_mode = (data>>7)&1;
1068 this->pm_mode = (data>>6)&1;
1069
1070 setRythmMode(this, data);
1071 if (this->rythm_mode) {
1072 if (data&0x10) keyOn_BD(this); else keyOff_BD(this);
1073 if (data&0x08) keyOn_SD(this); else keyOff_SD(this);
1074 if (data&0x04) keyOn_TOM(this); else keyOff_TOM(this);
1075 if (data&0x02) keyOn_CYM(this); else keyOff_CYM(this);
1076 if (data&0x01) keyOn_HH(this); else keyOff_HH(this);
1077 }
1078 slotUpdateAll(&this->ch[6].mod);
1079 slotUpdateAll(&this->ch[6].car);
1080 slotUpdateAll(&this->ch[7].mod);
1081 slotUpdateAll(&this->ch[7].car);
1082 slotUpdateAll(&this->ch[8].mod);
1083 slotUpdateAll(&this->ch[8].car);
1084
1085 this->reg[rg] = data;
1086 break;
1087 }
1088 if ((rg&0xf) > 8) {
1089 // 0xa9-0xaf 0xb9-0xbf
1090 break;
1091 }
1092 if (!(rg&0x10)) {
1093 // 0xa0-0xa8
1094 int c = rg-0xa0;
1095 int fNum = data + ((this->reg[rg+0x10]&3)<<8);
1096 int block = (this->reg[rg+0x10]>>2)&7;
1097 channelSetFnumber(&this->ch[c], fNum);
1098 switch (c) {
1099 case 7: this->noiseA_dphase = dphaseNoiseTable[fNum][block];
1100 break;
1101 case 8: this->noiseB_dphase = dphaseNoiseTable[fNum][block];
1102 break;
1103 }
1104 slotUpdateAll(&this->ch[c].car);
1105 slotUpdateAll(&this->ch[c].mod);
1106 this->reg[rg] = data;
1107 } else {
1108 // 0xb0-0xb8
1109 int c = rg-0xb0;
1110 int fNum = ((data&3)<<8) + this->reg[rg-0x10];
1111 int block = (data>>2)&7;
1112 channelSetFnumber(&this->ch[c], fNum);
1113 channelSetBlock(&this->ch[c], block);
1114 switch (c) {
1115 case 7: this->noiseA_dphase = dphaseNoiseTable[fNum][block];
1116 break;
1117 case 8: this->noiseB_dphase = dphaseNoiseTable[fNum][block];
1118 break;
1119 }
1120 if (data&0x20)
1121 keyOn(&this->ch[c]);
1122 else
1123 keyOff(&this->ch[c]);
1124 slotUpdateAll(&this->ch[c].mod);
1125 slotUpdateAll(&this->ch[c].car);
1126 this->reg[rg] = data;
1127 }
1128 break;
1129 }
1130 case 0xc0: {
1131 if (rg > 0xc8)
1132 break;
1133 int c = rg-0xC0;
1134 this->slot[c*2]->patch.FB = (data>>1)&7;
1135 this->ch[c].alg = data&1;
1136 this->reg[rg] = data;
1137 }
1138 }
1139
1140 //TODO only for registers that influence sound
1141 checkMute(this);
1142}
1143
1144byte OPL_readReg(struct Y8950* this, byte rg)
1145{
1146 byte result;
1147 switch (rg) {
1148 case 0x05: // (KEYBOARD IN)
1149 result = 0xff;
1150 break;
1151
1152 case 0x0f: // ADPCM-DATA
1153 case 0x13: // ???
1154 case 0x14: // ???
1155 case 0x1a: // PCM-DATA
1156 result = ADPCM_readReg(&this->adpcm, rg);
1157 break;
1158
1159 case 0x19: // I/O DATA TODO
1160 /* result = ~(switchGetAudio() ? 0 : 0x04); */
1161 result = 0;
1162 break;
1163 default:
1164 result = 255;
1165 }
1166 //PRT_DEBUG("Y8950 read " << (int)rg<<" "<<(int)result);
1167 return result;
1168}
1169
1170byte OPL_readStatus(struct Y8950* this)
1171{
1172 OPL_setStatus(this, STATUS_BUF_RDY); // temp hack
1173 byte tmp = this->status & (0x80 | this->statusMask);
1174 //PRT_DEBUG("Y8950 read status " << (int)tmp);
1175 return tmp | 0x06; // bit 1 and 2 are always 1
1176}
1177
1178
1179void OPL_setStatus(struct Y8950* this, byte flags)
1180{
1181 this->status |= flags;
1182 if (this->status & this->statusMask) {
1183 this->status |= 0x80;
1184 /* irq.set(); */
1185 }
1186}
1187void OPL_resetStatus(struct Y8950* this, byte flags)
1188{
1189 this->status &= ~flags;
1190 if (!(this->status & this->statusMask)) {
1191 this->status &= 0x7f;
1192 /* irq.reset(); */
1193 }
1194}
1195void OPL_changeStatusMask(struct Y8950* this, byte newMask)
1196{
1197 this->statusMask = newMask;
1198 this->status &= this->statusMask;
1199 if (this->status) {
1200 this->status |= 0x80;
1201 /* irq.set(); */
1202 } else {
1203 this->status &= 0x7f;
1204 /* irq.reset(); */
1205 }
1206}