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