summaryrefslogtreecommitdiff
path: root/apps/codecs/libgme/ym2612_emu.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/libgme/ym2612_emu.c')
-rw-r--r--apps/codecs/libgme/ym2612_emu.c1359
1 files changed, 1359 insertions, 0 deletions
diff --git a/apps/codecs/libgme/ym2612_emu.c b/apps/codecs/libgme/ym2612_emu.c
new file mode 100644
index 0000000000..a2f32d30ca
--- /dev/null
+++ b/apps/codecs/libgme/ym2612_emu.c
@@ -0,0 +1,1359 @@
1// Game_Music_Emu $vers. http://www.slack.net/~ant/
2
3// Based on Gens 2.10 ym2612.c
4
5#include "ym2612_emu.h"
6
7#include <assert.h>
8#include <stdlib.h>
9#include <string.h>
10#include <limits.h>
11#include <stdio.h>
12#include <math.h>
13
14/* Copyright (C) 2002 Stéphane Dallongeville (gens AT consolemul.com) */
15/* Copyright (C) 2004-2007 Shay Green. This module is free software; you
16can redistribute it and/or modify it under the terms of the GNU Lesser
17General Public License as published by the Free Software Foundation; either
18version 2.1 of the License, or (at your option) any later version. This
19module is distributed in the hope that it will be useful, but WITHOUT ANY
20WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
21FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
22details. You should have received a copy of the GNU Lesser General Public
23License along with this module; if not, write to the Free Software Foundation,
24Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
25
26// This is mostly the original source in its C style and all.
27//
28// Somewhat optimized and simplified. Uses a template to generate the many
29// variants of Update_Chan. Rewrote header file. In need of full rewrite by
30// someone more familiar with FM sound and the YM2612. Has some inaccuracies
31// compared to the Sega Genesis sound, particularly being mixed at such a
32// high sample accuracy (the Genesis sounds like it has only 8 bit samples).
33// - Shay
34
35// Ported again to c by gama.
36// Not sure if performance is better than the original c version.
37
38#if !defined(ROCKBOX)
39 #define YM2612_CALCUL_TABLES
40#else
41 #include "ymtables.h"
42#endif
43
44const int output_bits = 14;
45
46static const unsigned char DT_DEF_TAB [4 * 32] ICONST_ATTR =
47{
48// FD = 0
49 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51
52// FD = 1
53 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
54 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7, 8, 8, 8, 8,
55
56// FD = 2
57 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5,
58 5, 6, 6, 7, 8, 8, 9, 10, 11, 12, 13, 14, 16, 16, 16, 16,
59
60// FD = 3
61 2, 2, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7,
62 8 , 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 20, 22, 22, 22, 22
63};
64
65static const unsigned char FKEY_TAB [16] ICONST_ATTR =
66{
67 0, 0, 0, 0,
68 0, 0, 0, 1,
69 2, 3, 3, 3,
70 3, 3, 3, 3
71};
72
73static const unsigned char LFO_AMS_TAB [4] ICONST_ATTR =
74{
75 31, 4, 1, 0
76};
77
78static const unsigned char LFO_FMS_TAB [8] ICONST_ATTR =
79{
80 LFO_FMS_BASE * 0, LFO_FMS_BASE * 1,
81 LFO_FMS_BASE * 2, LFO_FMS_BASE * 3,
82 LFO_FMS_BASE * 4, LFO_FMS_BASE * 6,
83 LFO_FMS_BASE * 12, LFO_FMS_BASE * 24
84};
85
86int in0, in1, in2, in3; // current phase calculation
87// int en0, en1, en2, en3; // current enveloppe calculation
88
89inline void set_seg( struct slot_t* s, int seg )
90{
91 s->env_xor = 0;
92 s->env_max = INT_MAX;
93 s->SEG = seg;
94 if ( seg & 4 )
95 {
96 s->env_xor = ENV_MASK;
97 s->env_max = ENV_MASK;
98 }
99}
100
101inline void YM2612_Special_Update(void) { }
102
103void KEY_ON( struct channel_* ch, struct tables_t *g, int nsl )
104{
105 struct slot_t *SL = &(ch->SLOT [nsl]); // on recupere le bon pointeur de slot
106
107 if (SL->Ecurp == RELEASE) // la touche est-elle rel'chee ?
108 {
109 SL->Fcnt = 0;
110
111 // Fix Ecco 2 splash sound
112
113 SL->Ecnt = (g->DECAY_TO_ATTACK [g->ENV_TAB [SL->Ecnt >> ENV_LBITS]] + ENV_ATTACK) & SL->ChgEnM;
114 SL->ChgEnM = ~0;
115
116// SL->Ecnt = g.DECAY_TO_ATTACK [g.ENV_TAB [SL->Ecnt >> ENV_LBITS]] + ENV_ATTACK;
117// SL->Ecnt = 0;
118
119 SL->Einc = SL->EincA;
120 SL->Ecmp = ENV_DECAY;
121 SL->Ecurp = ATTACK;
122 }
123}
124
125
126void KEY_OFF( struct channel_* ch, struct tables_t *g, int nsl )
127{
128 struct slot_t *SL = &(ch->SLOT [nsl]); // on recupere le bon pointeur de slot
129
130 if (SL->Ecurp != RELEASE) // la touche est-elle appuyee ?
131 {
132 if (SL->Ecnt < ENV_DECAY) // attack phase ?
133 {
134 SL->Ecnt = (g->ENV_TAB [SL->Ecnt >> ENV_LBITS] << ENV_LBITS) + ENV_DECAY;
135 }
136
137 SL->Einc = SL->EincR;
138 SL->Ecmp = ENV_END;
139 SL->Ecurp = RELEASE;
140 }
141}
142
143
144int SLOT_SET( struct Ym2612_Impl* impl, int Adr, int data )
145{
146 int nch = Adr & 3;
147 if ( nch == 3 )
148 return 1;
149
150 struct tables_t *g = &impl->g;
151 struct state_t *YM2612 = &impl->YM2612;
152 struct channel_* ch = &YM2612->CHANNEL [nch + (Adr & 0x100 ? 3 : 0)];
153 struct slot_t* sl = &ch->SLOT [(Adr >> 2) & 3];
154
155 switch ( Adr & 0xF0 )
156 {
157 case 0x30:
158 if ( (sl->MUL = (data & 0x0F)) != 0 ) sl->MUL <<= 1;
159 else sl->MUL = 1;
160
161 sl->DT = (int*) g->DT_TAB [(data >> 4) & 7];
162
163 ch->SLOT [0].Finc = -1;
164
165 break;
166
167 case 0x40:
168 sl->TL = data & 0x7F;
169
170 // SOR2 do a lot of TL adjustement and this fix R.Shinobi jump sound...
171 YM2612_Special_Update();
172
173#if ((ENV_HBITS - 7) < 0)
174 sl->TLL = sl->TL >> (7 - ENV_HBITS);
175#else
176 sl->TLL = sl->TL << (ENV_HBITS - 7);
177#endif
178
179 break;
180
181 case 0x50:
182 sl->KSR_S = 3 - (data >> 6);
183
184 ch->SLOT [0].Finc = -1;
185
186 if (data &= 0x1F) sl->AR = (int*) &g->AR_TAB [data << 1];
187 else sl->AR = (int*) &g->NULL_RATE [0];
188
189 sl->EincA = sl->AR [sl->KSR];
190 if (sl->Ecurp == ATTACK) sl->Einc = sl->EincA;
191 break;
192
193 case 0x60:
194 if ( (sl->AMSon = (data & 0x80)) != 0 ) sl->AMS = ch->AMS;
195 else sl->AMS = 31;
196
197 if (data &= 0x1F) sl->DR = (int*) &g->DR_TAB [data << 1];
198 else sl->DR = (int*) &g->NULL_RATE [0];
199
200 sl->EincD = sl->DR [sl->KSR];
201 if (sl->Ecurp == DECAY) sl->Einc = sl->EincD;
202 break;
203
204 case 0x70:
205 if (data &= 0x1F) sl->SR = (int*) &g->DR_TAB [data << 1];
206 else sl->SR = (int*) &g->NULL_RATE [0];
207
208 sl->EincS = sl->SR [sl->KSR];
209 if ((sl->Ecurp == SUBSTAIN) && (sl->Ecnt < ENV_END)) sl->Einc = sl->EincS;
210 break;
211
212 case 0x80:
213 sl->SLL = g->SL_TAB [data >> 4];
214
215 sl->RR = (int*) &g->DR_TAB [((data & 0xF) << 2) + 2];
216
217 sl->EincR = sl->RR [sl->KSR];
218 if ((sl->Ecurp == RELEASE) && (sl->Ecnt < ENV_END)) sl->Einc = sl->EincR;
219 break;
220
221 case 0x90:
222 // SSG-EG envelope shapes :
223 /*
224 E At Al H
225
226 1 0 0 0 \\\\
227 1 0 0 1 \___
228 1 0 1 0 \/\/
229 1 0 1 1 \
230 1 1 0 0 ////
231 1 1 0 1 /
232 1 1 1 0 /\/\
233 1 1 1 1 /___
234
235 E = SSG-EG enable
236 At = Start negate
237 Al = Altern
238 H = Hold */
239
240 set_seg( sl, (data & 8) ? (data & 0x0F) : 0 );
241 break;
242 }
243
244 return 0;
245}
246
247
248int CHANNEL_SET( struct state_t* YM2612, int Adr, int data )
249{
250 int num = Adr & 3;
251 if ( num == 3 )
252 return 1;
253
254 struct channel_* ch = &YM2612->CHANNEL [num + (Adr & 0x100 ? 3 : 0)];
255
256 switch ( Adr & 0xFC )
257 {
258 case 0xA0:
259 YM2612_Special_Update();
260
261 ch->FNUM [0] = (ch->FNUM [0] & 0x700) + data;
262 ch->KC [0] = (ch->FOCT [0] << 2) | FKEY_TAB [ch->FNUM [0] >> 7];
263
264 ch->SLOT [0].Finc = -1;
265 break;
266
267 case 0xA4:
268 YM2612_Special_Update();
269
270 ch->FNUM [0] = (ch->FNUM [0] & 0x0FF) + ((data & 0x07) << 8);
271 ch->FOCT [0] = (data & 0x38) >> 3;
272 ch->KC [0] = (ch->FOCT [0] << 2) | FKEY_TAB [ch->FNUM [0] >> 7];
273
274 ch->SLOT [0].Finc = -1;
275 break;
276
277 case 0xA8:
278 if ( Adr < 0x100 )
279 {
280 num++;
281
282 YM2612_Special_Update();
283
284 YM2612->CHANNEL [2].FNUM [num] = (YM2612->CHANNEL [2].FNUM [num] & 0x700) + data;
285 YM2612->CHANNEL [2].KC [num] = (YM2612->CHANNEL [2].FOCT [num] << 2) |
286 FKEY_TAB [YM2612->CHANNEL [2].FNUM [num] >> 7];
287
288 YM2612->CHANNEL [2].SLOT [0].Finc = -1;
289 }
290 break;
291
292 case 0xAC:
293 if ( Adr < 0x100 )
294 {
295 num++;
296
297 YM2612_Special_Update();
298
299 YM2612->CHANNEL [2].FNUM [num] = (YM2612->CHANNEL [2].FNUM [num] & 0x0FF) + ((data & 0x07) << 8);
300 YM2612->CHANNEL [2].FOCT [num] = (data & 0x38) >> 3;
301 YM2612->CHANNEL [2].KC [num] = (YM2612->CHANNEL [2].FOCT [num] << 2) |
302 FKEY_TAB [YM2612->CHANNEL [2].FNUM [num] >> 7];
303
304 YM2612->CHANNEL [2].SLOT [0].Finc = -1;
305 }
306 break;
307
308 case 0xB0:
309 if ( ch->ALGO != (data & 7) )
310 {
311 // Fix VectorMan 2 heli sound (level 1)
312 YM2612_Special_Update();
313
314 ch->ALGO = data & 7;
315
316 ch->SLOT [0].ChgEnM = 0;
317 ch->SLOT [1].ChgEnM = 0;
318 ch->SLOT [2].ChgEnM = 0;
319 ch->SLOT [3].ChgEnM = 0;
320 }
321
322 ch->FB = 9 - ((data >> 3) & 7); // Real thing ?
323
324// if (ch->FB = ((data >> 3) & 7)) ch->FB = 9 - ch->FB; // Thunder force 4 (music stage 8), Gynoug, Aladdin bug sound...
325// else ch->FB = 31;
326 break;
327
328 case 0xB4: {
329 YM2612_Special_Update();
330
331 ch->LEFT = 0 - ((data >> 7) & 1);
332 ch->RIGHT = 0 - ((data >> 6) & 1);
333
334 ch->AMS = LFO_AMS_TAB [(data >> 4) & 3];
335 ch->FMS = LFO_FMS_TAB [data & 7];
336
337 int i;
338 for ( i = 0; i < 4; i++ )
339 {
340 struct slot_t* sl = &ch->SLOT [i];
341 sl->AMS = (sl->AMSon ? ch->AMS : 31);
342 }
343 break;
344 }
345 }
346
347 return 0;
348}
349
350
351int YM_SET( struct Ym2612_Impl* impl, int Adr, int data )
352{
353 struct state_t* YM2612 = &impl->YM2612;
354 struct tables_t* g = &impl->g;
355 switch ( Adr )
356 {
357 case 0x22:
358 if (data & 8) // LFO enable
359 {
360 // Cool Spot music 1, LFO modified severals time which
361 // distord the sound, have to check that on a real genesis...
362
363 g->LFOinc = g->LFO_INC_TAB [data & 7];
364 }
365 else
366 {
367 g->LFOinc = g->LFOcnt = 0;
368 }
369 break;
370
371 case 0x24:
372 YM2612->TimerA = (YM2612->TimerA & 0x003) | (((int) data) << 2);
373
374 if (YM2612->TimerAL != (1024 - YM2612->TimerA) << 12)
375 {
376 YM2612->TimerAcnt = YM2612->TimerAL = (1024 - YM2612->TimerA) << 12;
377 }
378 break;
379
380 case 0x25:
381 YM2612->TimerA = (YM2612->TimerA & 0x3FC) | (data & 3);
382
383 if (YM2612->TimerAL != (1024 - YM2612->TimerA) << 12)
384 {
385 YM2612->TimerAcnt = YM2612->TimerAL = (1024 - YM2612->TimerA) << 12;
386 }
387 break;
388
389 case 0x26:
390 YM2612->TimerB = data;
391
392 if (YM2612->TimerBL != (256 - YM2612->TimerB) << (4 + 12))
393 {
394 YM2612->TimerBcnt = YM2612->TimerBL = (256 - YM2612->TimerB) << (4 + 12);
395 }
396 break;
397
398 case 0x27:
399 // Parametre divers
400 // b7 = CSM MODE
401 // b6 = 3 slot mode
402 // b5 = reset b
403 // b4 = reset a
404 // b3 = timer enable b
405 // b2 = timer enable a
406 // b1 = load b
407 // b0 = load a
408
409 if ((data ^ YM2612->Mode) & 0x40)
410 {
411 // We changed the channel 2 mode, so recalculate phase step
412 // This fix the punch sound in Street of Rage 2
413
414 YM2612_Special_Update();
415
416 YM2612->CHANNEL [2].SLOT [0].Finc = -1; // recalculate phase step
417 }
418
419// if ((data & 2) && (YM2612->Status & 2)) YM2612->TimerBcnt = YM2612->TimerBL;
420// if ((data & 1) && (YM2612->Status & 1)) YM2612->TimerAcnt = YM2612->TimerAL;
421
422// YM2612->Status &= (~data >> 4); // Reset du Status au cas ou c'est demande
423 YM2612->Status &= (~data >> 4) & (data >> 2); // Reset Status
424
425 YM2612->Mode = data;
426 break;
427
428 case 0x28: {
429 int nch = data & 3;
430 if ( nch == 3 )
431 return 1;
432 if ( data & 4 )
433 nch += 3;
434 struct channel_* ch = &YM2612->CHANNEL [nch];
435
436 YM2612_Special_Update();
437
438 if (data & 0x10) KEY_ON(ch, g, S0); // On appuie sur la touche pour le slot 1
439 else KEY_OFF(ch, g, S0); // On rel'che la touche pour le slot 1
440 if (data & 0x20) KEY_ON(ch, g, S1); // On appuie sur la touche pour le slot 3
441 else KEY_OFF(ch, g, S1); // On rel'che la touche pour le slot 3
442 if (data & 0x40) KEY_ON(ch, g, S2); // On appuie sur la touche pour le slot 2
443 else KEY_OFF(ch, g, S2); // On rel'che la touche pour le slot 2
444 if (data & 0x80) KEY_ON(ch, g, S3); // On appuie sur la touche pour le slot 4
445 else KEY_OFF(ch, g, S3); // On rel'che la touche pour le slot 4
446 break;
447 }
448
449 case 0x2B:
450 if (YM2612->DAC ^ (data & 0x80)) YM2612_Special_Update();
451
452 YM2612->DAC = data & 0x80; // activation/desactivation du DAC
453 break;
454 }
455
456 return 0;
457}
458
459#if defined(ROCKBOX)
460double fabs(double x)
461{
462 if (x < 0.0) return -x;
463 return x;
464}
465
466double ipow(double a,int b)
467{
468 if (b < 0) {
469 a = 1.0 / a;
470 b = -b;
471 }
472 double result = 1.0;
473 while(b) {
474 if (b & 1) result*=a;
475 a *= a;
476 b >>= 1;
477 }
478 return result;
479}
480#endif
481
482void impl_reset( struct Ym2612_Impl* impl );
483void impl_set_rate( struct Ym2612_Impl* impl, double sample_rate, double clock_rate )
484{
485 assert( sample_rate );
486 assert( !clock_rate || clock_rate > sample_rate );
487
488 int i;
489
490 // 144 = 12 * (prescale * 2) = 12 * 6 * 2
491 // prescale set to 6 by default
492
493 double Frequence = (clock_rate ? clock_rate / sample_rate / 144.0 : 1.0);
494 if ( fabs( Frequence - 1.0 ) < 0.0000001 )
495 Frequence = 1.0;
496 impl->YM2612.TimerBase = (int) (Frequence * 4096.0);
497
498 // Tableau TL :
499 // [0 - 4095] = +output [4095 - ...] = +output overflow (fill with 0)
500 // [12288 - 16383] = -output [16384 - ...] = -output overflow (fill with 0)
501
502 for ( i = 0; i < TL_LENGHT; i++ )
503 {
504 if (i >= PG_CUT_OFF) // YM2612 cut off sound after 78 dB (14 bits output ?)
505 {
506 impl->g.TL_TAB [TL_LENGHT + i] = impl->g.TL_TAB [i] = 0;
507 }
508 else
509 {
510 // Decibel -> Voltage
511 #ifdef YM2612_CALCUL_TABLES
512 impl->g.TL_TAB [i] = (int) (MAX_OUT / pow( 10.0, ENV_STEP / 20.0f * i ));
513 #else
514 impl->g.TL_TAB [i] = tl_coeff [i];
515 #endif
516 impl->g.TL_TAB [TL_LENGHT + i] = -impl->g.TL_TAB [i];
517 }
518 }
519
520 // Tableau SIN :
521 // impl->g.SIN_TAB [x] [y] = sin(x) * y;
522 // x = phase and y = volume
523
524 impl->g.SIN_TAB [0] = impl->g.SIN_TAB [SIN_LENGHT / 2] = PG_CUT_OFF;
525
526 for ( i = 1; i <= SIN_LENGHT / 4; i++ )
527 {
528 // Sinus in dB
529 #ifdef YM2612_CALCUL_TABLES
530 double x = 20 * log10( 1 / sin( 2.0 * PI * i / SIN_LENGHT ) ); // convert to dB
531
532 int j = (int) (x / ENV_STEP); // Get TL range
533
534 if (j > PG_CUT_OFF) j = (int) PG_CUT_OFF;
535 #else
536 int j = sindb_coeff [i-1];
537 #endif
538
539 impl->g.SIN_TAB [i] = impl->g.SIN_TAB [(SIN_LENGHT / 2) - i] = j;
540 impl->g.SIN_TAB [(SIN_LENGHT / 2) + i] = impl->g.SIN_TAB [SIN_LENGHT - i] = TL_LENGHT + j;
541 }
542
543 // Tableau LFO (LFO wav) :
544
545 for ( i = 0; i < LFO_LENGHT; i++ )
546 {
547 #ifdef YM2612_CALCUL_TABLES
548 double x = 1 + sin( 2.0 * PI * i * (1.0 / LFO_LENGHT) ); // Sinus
549 x *= 11.8 / ENV_STEP / 2; // ajusted to MAX enveloppe modulation
550
551 impl->g.LFO_ENV_TAB [i] = (int) x;
552
553 x = sin( 2.0 * PI * i * (1.0 / LFO_LENGHT) ); // Sinus
554 x *= (1 << (LFO_HBITS - 1)) - 1;
555
556 impl->g.LFO_FREQ_TAB [i] = (int) x;
557 #else
558 impl->g.LFO_ENV_TAB [i] = lfo_env_coeff [i];
559 impl->g.LFO_FREQ_TAB [i] = lfo_freq_coeff [i];
560 #endif
561 }
562
563 // Tableau Enveloppe :
564 // impl->g.ENV_TAB [0] -> impl->g.ENV_TAB [ENV_LENGHT - 1] = attack curve
565 // impl->g.ENV_TAB [ENV_LENGHT] -> impl->g.ENV_TAB [2 * ENV_LENGHT - 1] = decay curve
566
567 for ( i = 0; i < ENV_LENGHT; i++ )
568 {
569 // Attack curve (x^8 - music level 2 Vectorman 2)
570 #if defined(ROCKBOX)
571 double x = ipow( ((ENV_LENGHT - 1) - i) / (double) ENV_LENGHT, 8.0 );
572 #else
573 double x = pow( ((ENV_LENGHT - 1) - i) / (double) ENV_LENGHT, 8.0 );
574 #endif
575 x *= ENV_LENGHT;
576
577 impl->g.ENV_TAB [i] = (int) x;
578
579 // Decay curve (just linear)
580 impl->g.ENV_TAB [ENV_LENGHT + i] = i;
581 }
582 for ( i = 0; i < 8; i++ )
583 impl->g.ENV_TAB [i + ENV_LENGHT * 2] = 0;
584
585 impl->g.ENV_TAB [ENV_END >> ENV_LBITS] = ENV_LENGHT - 1; // for the stopped state
586
587 // Tableau pour la conversion Attack -> Decay and Decay -> Attack
588
589 int j = ENV_LENGHT - 1;
590 for ( i = 0; i < ENV_LENGHT; i++ )
591 {
592 while ( j && impl->g.ENV_TAB [j] < i )
593 j--;
594
595 impl->g.DECAY_TO_ATTACK [i] = j << ENV_LBITS;
596 }
597
598 // Tableau pour le Substain Level
599
600 for ( i = 0; i < 15; i++ )
601 {
602 double x = i * 3 / ENV_STEP; // 3 and not 6 (Mickey Mania first music for test)
603
604 impl->g.SL_TAB [i] = ((int) x << ENV_LBITS) + ENV_DECAY;
605 }
606
607 impl->g.SL_TAB [15] = ((ENV_LENGHT - 1) << ENV_LBITS) + ENV_DECAY; // special case : volume off
608
609 // Tableau Frequency Step
610 {
611 // 0.5 because MUL = value * 2
612 #if SIN_LBITS + SIN_HBITS - (21 - 7) < 0
613 double const factor = 0.5 / (1 << ((21 - 7) - SIN_LBITS - SIN_HBITS)) * Frequence;
614 #else
615 double const factor = 0.5 * (1 << (SIN_LBITS + SIN_HBITS - (21 - 7))) * Frequence;
616 #endif
617 for ( i = 0; i < 2048; i++ )
618 impl->g.FINC_TAB [i] = (unsigned) (i * factor);
619 }
620
621 // Tableaux Attack & Decay Rate
622
623 for ( i = 0; i < 4; i++ )
624 {
625 impl->g.AR_TAB [i] = 0;
626 impl->g.DR_TAB [i] = 0;
627 }
628
629 for ( i = 0; i < 60; i++ )
630 {
631 double x =
632 (1.0 + ((i & 3) * 0.25)) * // bits 0-1 : x1.00, x1.25, x1.50, x1.75
633 (ENV_LENGHT << ENV_LBITS) * // on ajuste pour le tableau impl->g.ENV_TAB
634 Frequence *
635 (1 << (i >> 2)); // bits 2-5 : shift bits (x2^0 - x2^15)
636
637 impl->g.AR_TAB [i + 4] = (unsigned int) (x / AR_RATE);
638 impl->g.DR_TAB [i + 4] = (unsigned int) (x / DR_RATE);
639 }
640
641 for ( i = 64; i < 96; i++ )
642 {
643 impl->g.AR_TAB [i] = impl->g.AR_TAB [63];
644 impl->g.DR_TAB [i] = impl->g.DR_TAB [63];
645
646 impl->g.NULL_RATE [i - 64] = 0;
647 }
648
649 for ( i = 96; i < 128; i++ )
650 impl->g.AR_TAB [i] = 0;
651
652 // Tableau Detune
653 {
654 #if SIN_LBITS + SIN_HBITS - 21 < 0
655 double const factor = 1.0 / (1 << (21 - SIN_LBITS - SIN_HBITS)) * Frequence;
656 #else
657 double const factor = (1 << (SIN_LBITS + SIN_HBITS - 21)) * Frequence;
658 #endif
659 for ( i = 0; i < 4; i++ )
660 {
661 int j;
662 for ( j = 0; j < 32; j++ )
663 {
664 double y = DT_DEF_TAB [(i << 5) + j] * factor;
665
666 impl->g.DT_TAB [i + 0] [j] = (int) y;
667 impl->g.DT_TAB [i + 4] [j] = (int) -y;
668 }
669 }
670 }
671
672 // Tableau LFO
673 impl->g.LFO_INC_TAB [0] = (unsigned) (3.98 * (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
674 impl->g.LFO_INC_TAB [1] = (unsigned) (5.56 * (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
675 impl->g.LFO_INC_TAB [2] = (unsigned) (6.02 * (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
676 impl->g.LFO_INC_TAB [3] = (unsigned) (6.37 * (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
677 impl->g.LFO_INC_TAB [4] = (unsigned) (6.88 * (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
678 impl->g.LFO_INC_TAB [5] = (unsigned) (9.63 * (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
679 impl->g.LFO_INC_TAB [6] = (unsigned) (48.1 * (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
680 impl->g.LFO_INC_TAB [7] = (unsigned) (72.2 * (1 << (LFO_HBITS + LFO_LBITS)) / sample_rate);
681
682 impl_reset( impl );
683}
684
685const char* Ym2612_set_rate( struct Ym2612_Emu* this, double sample_rate, double clock_rate )
686{
687// Only set rates if necessary
688#if defined(ROCKBOX)
689 static double last_sample_rate = 0.0, last_clock_rate = 0.0;
690 if (last_sample_rate == sample_rate && last_clock_rate == clock_rate) return 0;
691#endif
692 memset( &this->impl.YM2612, 0, sizeof this->impl.YM2612 );
693 impl_set_rate( &this->impl, sample_rate, clock_rate );
694
695 return 0;
696}
697
698inline void write0( struct Ym2612_Impl* impl, int opn_addr, int data )
699{
700 assert( (unsigned) data <= 0xFF );
701
702 if ( opn_addr < 0x30 )
703 {
704 impl->YM2612.REG [0] [opn_addr] = data;
705 YM_SET( impl, opn_addr, data );
706 }
707 else if ( impl->YM2612.REG [0] [opn_addr] != data )
708 {
709 impl->YM2612.REG [0] [opn_addr] = data;
710
711 if ( opn_addr < 0xA0 )
712 SLOT_SET( impl, opn_addr, data );
713 else
714 CHANNEL_SET( &impl->YM2612, opn_addr, data );
715 }
716}
717
718inline void write1( struct Ym2612_Impl* impl, int opn_addr, int data )
719{
720 assert( (unsigned) data <= 0xFF );
721
722 if ( opn_addr >= 0x30 && impl->YM2612.REG [1] [opn_addr] != data )
723 {
724 impl->YM2612.REG [1] [opn_addr] = data;
725
726 if ( opn_addr < 0xA0 )
727 SLOT_SET( impl, opn_addr + 0x100, data );
728 else
729 CHANNEL_SET( &impl->YM2612, opn_addr + 0x100, data );
730 }
731}
732
733void impl_reset( struct Ym2612_Impl* impl )
734{
735 impl->g.LFOcnt = 0;
736 impl->YM2612.TimerA = 0;
737 impl->YM2612.TimerAL = 0;
738 impl->YM2612.TimerAcnt = 0;
739 impl->YM2612.TimerB = 0;
740 impl->YM2612.TimerBL = 0;
741 impl->YM2612.TimerBcnt = 0;
742 impl->YM2612.DAC = 0;
743
744 impl->YM2612.Status = 0;
745
746 int i;
747 for ( i = 0; i < ym2612_channel_count; i++ )
748 {
749 struct channel_* ch = &impl->YM2612.CHANNEL [i];
750
751 ch->LEFT = ~0;
752 ch->RIGHT = ~0;
753 ch->ALGO = 0;
754 ch->FB = 31;
755 ch->FMS = 0;
756 ch->AMS = 0;
757
758 int j;
759 for ( j = 0 ;j < 4 ; j++ )
760 {
761 ch->S0_OUT [j] = 0;
762 ch->FNUM [j] = 0;
763 ch->FOCT [j] = 0;
764 ch->KC [j] = 0;
765
766 ch->SLOT [j].Fcnt = 0;
767 ch->SLOT [j].Finc = 0;
768 ch->SLOT [j].Ecnt = ENV_END; // Put it at the end of Decay phase...
769 ch->SLOT [j].Einc = 0;
770 ch->SLOT [j].Ecmp = 0;
771 ch->SLOT [j].Ecurp = RELEASE;
772
773 ch->SLOT [j].ChgEnM = 0;
774 }
775 }
776
777 for ( i = 0; i < 0x100; i++ )
778 {
779 impl->YM2612.REG [0] [i] = -1;
780 impl->YM2612.REG [1] [i] = -1;
781 }
782
783 for ( i = 0xB6; i >= 0xB4; i-- )
784 {
785 write0( impl, i, 0xC0 );
786 write1( impl, i, 0xC0 );
787 }
788
789 for ( i = 0xB2; i >= 0x22; i-- )
790 {
791 write0( impl, i, 0 );
792 write1( impl, i, 0 );
793 }
794
795 write0( impl, 0x2A, 0x80 );
796}
797
798void Ym2612_reset( struct Ym2612_Emu* this )
799{
800 impl_reset( &this->impl );
801}
802
803void Ym2612_write0( struct Ym2612_Emu* this, int addr, int data )
804{
805 write0( &this->impl, addr, data );
806}
807
808void Ym2612_write1( struct Ym2612_Emu* this, int addr, int data )
809{
810 write1( &this->impl, addr, data );
811}
812
813void Ym2612_mute_voices( struct Ym2612_Emu* this, int mask ) { this->impl.mute_mask = mask; }
814
815static void update_envelope_( struct slot_t* sl )
816{
817 switch ( sl->Ecurp )
818 {
819 case 0:
820 // Env_Attack_Next
821
822 // Verified with Gynoug even in HQ (explode SFX)
823 sl->Ecnt = ENV_DECAY;
824
825 sl->Einc = sl->EincD;
826 sl->Ecmp = sl->SLL;
827 sl->Ecurp = DECAY;
828 break;
829
830 case 1:
831 // Env_Decay_Next
832
833 // Verified with Gynoug even in HQ (explode SFX)
834 sl->Ecnt = sl->SLL;
835
836 sl->Einc = sl->EincS;
837 sl->Ecmp = ENV_END;
838 sl->Ecurp = SUBSTAIN;
839 break;
840
841 case 2:
842 // Env_Substain_Next(slot_t *SL)
843 if (sl->SEG & 8) // SSG envelope type
844 {
845 int release = sl->SEG & 1;
846
847 if ( !release )
848 {
849 // re KEY ON
850
851 // sl->Fcnt = 0;
852 // sl->ChgEnM = ~0;
853
854 sl->Ecnt = 0;
855 sl->Einc = sl->EincA;
856 sl->Ecmp = ENV_DECAY;
857 sl->Ecurp = ATTACK;
858 }
859
860 set_seg( sl, (sl->SEG << 1) & 4 );
861
862 if ( !release )
863 break;
864 }
865 // fall through
866
867 case 3:
868 // Env_Release_Next
869 sl->Ecnt = ENV_END;
870 sl->Einc = 0;
871 sl->Ecmp = ENV_END + 1;
872 break;
873
874 // default: no op
875 }
876}
877
878static inline void update_envelope( struct slot_t* sl )
879{
880 int ecmp = sl->Ecmp;
881 if ( (sl->Ecnt += sl->Einc) >= ecmp )
882 update_envelope_( sl );
883}
884
885
886typedef void (*ym2612_update_chan_t)( struct tables_t*, struct channel_*, short*, int );
887
888#define GET_CURRENT_PHASE \
889int in0 = ch->SLOT[S0].Fcnt; \
890int in1 = ch->SLOT[S1].Fcnt; \
891int in2 = ch->SLOT[S2].Fcnt; \
892int in3 = ch->SLOT[S3].Fcnt; \
893
894#define GET_CURRENT_LFO \
895int YM2612_LFOinc = g->LFOinc; \
896int YM2612_LFOcnt = g->LFOcnt + YM2612_LFOinc;
897
898#define CALC_EN( x ) \
899 int temp##x = ENV_TAB [ch->SLOT [S##x].Ecnt >> ENV_LBITS] + ch->SLOT [S##x].TLL; \
900 int en##x = ((temp##x ^ ch->SLOT [S##x].env_xor) + (env_LFO >> ch->SLOT [S##x].AMS)) & \
901 ((temp##x - ch->SLOT [S##x].env_max) >> 31);
902
903#define GET_ENV \
904int const env_LFO = g->LFO_ENV_TAB [YM2612_LFOcnt >> LFO_LBITS & LFO_MASK]; \
905short const* const ENV_TAB = g->ENV_TAB; \
906CALC_EN( 0 ) \
907CALC_EN( 1 ) \
908CALC_EN( 2 ) \
909CALC_EN( 3 ) \
910int const* const TL_TAB = g->TL_TAB;
911
912#define DO_FEEDBACK \
913int CH_S0_OUT_0 = ch->S0_OUT [0]; \
914{ \
915 int temp = in0 + ((CH_S0_OUT_0 + CH_S0_OUT_1) >> ch->FB); \
916 CH_S0_OUT_1 = CH_S0_OUT_0; \
917 CH_S0_OUT_0 = SINT( (temp >> SIN_LBITS) & SIN_MASK, en0 ); \
918} \
919
920#define SINT( i, o ) (TL_TAB [g->SIN_TAB [(i)] + (o)])
921
922#define DO_LIMIT \
923CH_OUTd >>= MAX_OUT_BITS - output_bits + 2; \
924
925#define UPDATE_PHASE_CYCLE \
926unsigned freq_LFO = ((g->LFO_FREQ_TAB [YM2612_LFOcnt >> LFO_LBITS & LFO_MASK] * \
927 ch->FMS) >> (LFO_HBITS - 1 + 1)) + (1 << (LFO_FMS_LBITS - 1)); \
928YM2612_LFOcnt += YM2612_LFOinc; \
929in0 += (ch->SLOT [S0].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1); \
930in1 += (ch->SLOT [S1].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1); \
931in2 += (ch->SLOT [S2].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1); \
932in3 += (ch->SLOT [S3].Finc * freq_LFO) >> (LFO_FMS_LBITS - 1);
933
934#define UPDATE_ENV \
935int t0 = buf [0] + (CH_OUTd & ch->LEFT); \
936int t1 = buf [1] + (CH_OUTd & ch->RIGHT); \
937update_envelope( &ch->SLOT [0] ); \
938update_envelope( &ch->SLOT [1] ); \
939update_envelope( &ch->SLOT [2] ); \
940update_envelope( &ch->SLOT [3] );
941
942#define DO_OUTPUT_0 \
943ch->S0_OUT [0] = CH_S0_OUT_0; \
944buf [0] = t0; \
945buf [1] = t1; \
946buf += 2; \
947
948#define DO_OUTPUT_1 \
949ch->S0_OUT [1] = CH_S0_OUT_1;
950
951#define UPDATE_PHASE \
952ch->SLOT [S0].Fcnt = in0; \
953ch->SLOT [S1].Fcnt = in1; \
954ch->SLOT [S2].Fcnt = in2; \
955ch->SLOT [S3].Fcnt = in3;
956
957void ym2612_update_chan0( struct tables_t* g, struct channel_* ch,
958 short* buf, int length )
959{
960 int not_end = ch->SLOT [S3].Ecnt - ENV_END;
961 int CH_S0_OUT_1 = ch->S0_OUT [1];
962
963 GET_CURRENT_PHASE
964 GET_CURRENT_LFO
965
966 if ( !not_end )
967 return;
968
969 do
970 {
971 GET_ENV
972 DO_FEEDBACK
973
974 int CH_OUTd;
975 int temp = in1 + CH_S0_OUT_1;
976 temp = in2 + SINT( (temp >> SIN_LBITS) & SIN_MASK, en1 );
977 temp = in3 + SINT( (temp >> SIN_LBITS) & SIN_MASK, en2 );
978 CH_OUTd = SINT( (temp >> SIN_LBITS) & SIN_MASK, en3 );
979
980 DO_LIMIT
981 UPDATE_PHASE_CYCLE
982 UPDATE_ENV
983 DO_OUTPUT_0
984 }
985 while ( --length );
986 DO_OUTPUT_1
987 UPDATE_PHASE
988}
989
990void ym2612_update_chan1( struct tables_t* g, struct channel_* ch,
991 short* buf, int length )
992{
993 int not_end = ch->SLOT [S3].Ecnt - ENV_END;
994 int CH_S0_OUT_1 = ch->S0_OUT [1];
995
996 GET_CURRENT_PHASE
997 GET_CURRENT_LFO
998
999 if ( !not_end )
1000 return;
1001
1002 do
1003 {
1004 GET_ENV
1005 DO_FEEDBACK
1006
1007 int CH_OUTd;
1008 int temp = in2 + CH_S0_OUT_1 + SINT( (in1 >> SIN_LBITS) & SIN_MASK, en1 );
1009 temp = in3 + SINT( (temp >> SIN_LBITS) & SIN_MASK, en2 );
1010 CH_OUTd = SINT( (temp >> SIN_LBITS) & SIN_MASK, en3 );
1011
1012 DO_LIMIT
1013 UPDATE_PHASE_CYCLE
1014 UPDATE_ENV
1015 DO_OUTPUT_0
1016 }
1017 while ( --length );
1018 DO_OUTPUT_1
1019 UPDATE_PHASE
1020}
1021
1022void ym2612_update_chan2( struct tables_t* g, struct channel_* ch,
1023 short* buf, int length )
1024{
1025 int not_end = ch->SLOT [S3].Ecnt - ENV_END;
1026 int CH_S0_OUT_1 = ch->S0_OUT [1];
1027
1028 GET_CURRENT_PHASE
1029 GET_CURRENT_LFO
1030
1031 if ( !not_end )
1032 return;
1033
1034 do
1035 {
1036 GET_ENV
1037 DO_FEEDBACK
1038
1039 int CH_OUTd;
1040 int temp = in2 + SINT( (in1 >> SIN_LBITS) & SIN_MASK, en1 );
1041 temp = in3 + CH_S0_OUT_1 + SINT( (temp >> SIN_LBITS) & SIN_MASK, en2 );
1042 CH_OUTd = SINT( (temp >> SIN_LBITS) & SIN_MASK, en3 );
1043
1044 DO_LIMIT
1045 UPDATE_PHASE_CYCLE
1046 UPDATE_ENV
1047 DO_OUTPUT_0
1048 }
1049 while ( --length );
1050 DO_OUTPUT_1
1051 UPDATE_PHASE
1052}
1053
1054void ym2612_update_chan3( struct tables_t* g, struct channel_* ch,
1055 short* buf, int length )
1056{
1057 int not_end = ch->SLOT [S3].Ecnt - ENV_END;
1058 int CH_S0_OUT_1 = ch->S0_OUT [1];
1059
1060 GET_CURRENT_PHASE
1061 GET_CURRENT_LFO
1062
1063 if ( !not_end )
1064 return;
1065
1066 do
1067 {
1068 GET_ENV
1069 DO_FEEDBACK
1070
1071 int CH_OUTd;
1072 int temp = in1 + CH_S0_OUT_1;
1073 temp = in3 + SINT( (temp >> SIN_LBITS) & SIN_MASK, en1 ) +
1074 SINT( (in2 >> SIN_LBITS) & SIN_MASK, en2 );
1075 CH_OUTd = SINT( (temp >> SIN_LBITS) & SIN_MASK, en3 );
1076
1077 DO_LIMIT
1078 UPDATE_PHASE_CYCLE
1079 UPDATE_ENV
1080 DO_OUTPUT_0
1081 }
1082 while ( --length );
1083 DO_OUTPUT_1
1084 UPDATE_PHASE
1085}
1086
1087void ym2612_update_chan4( struct tables_t* g, struct channel_* ch,
1088 short* buf, int length )
1089{
1090 int not_end = ch->SLOT [S3].Ecnt - ENV_END;
1091 not_end |= ch->SLOT [S1].Ecnt - ENV_END;
1092
1093 int CH_S0_OUT_1 = ch->S0_OUT [1];
1094
1095 GET_CURRENT_PHASE
1096 GET_CURRENT_LFO
1097
1098 if ( !not_end )
1099 return;
1100
1101 do
1102 {
1103 GET_ENV
1104 DO_FEEDBACK
1105
1106 int CH_OUTd;
1107 int temp = in3 + SINT( (in2 >> SIN_LBITS) & SIN_MASK, en2 );
1108 CH_OUTd = SINT( (temp >> SIN_LBITS) & SIN_MASK, en3 ) +
1109 SINT( ((in1 + CH_S0_OUT_1) >> SIN_LBITS) & SIN_MASK, en1 );
1110
1111 DO_LIMIT
1112 UPDATE_PHASE_CYCLE
1113 UPDATE_ENV
1114 DO_OUTPUT_0
1115 }
1116 while ( --length );
1117 DO_OUTPUT_1
1118 UPDATE_PHASE
1119}
1120
1121void ym2612_update_chan5( struct tables_t* g, struct channel_* ch,
1122 short* buf, int length )
1123{
1124 int not_end = ch->SLOT [S3].Ecnt - ENV_END;
1125 not_end |= ch->SLOT [S2].Ecnt - ENV_END;
1126 not_end |= ch->SLOT [S1].Ecnt - ENV_END;
1127
1128 int CH_S0_OUT_1 = ch->S0_OUT [1];
1129
1130 GET_CURRENT_PHASE
1131 GET_CURRENT_LFO
1132
1133 if ( !not_end )
1134 return;
1135
1136 do
1137 {
1138 GET_ENV
1139 DO_FEEDBACK
1140
1141 int CH_OUTd;
1142 int temp = CH_S0_OUT_1;
1143 CH_OUTd = SINT( ((in3 + temp) >> SIN_LBITS) & SIN_MASK, en3 ) +
1144 SINT( ((in1 + temp) >> SIN_LBITS) & SIN_MASK, en1 ) +
1145 SINT( ((in2 + temp) >> SIN_LBITS) & SIN_MASK, en2 );
1146
1147 DO_LIMIT
1148 UPDATE_PHASE_CYCLE
1149 UPDATE_ENV
1150 DO_OUTPUT_0
1151 }
1152 while ( --length );
1153 DO_OUTPUT_1
1154 UPDATE_PHASE
1155}
1156
1157void ym2612_update_chan6( struct tables_t* g, struct channel_* ch,
1158 short* buf, int length )
1159{
1160 int not_end = ch->SLOT [S3].Ecnt - ENV_END;
1161 not_end |= ch->SLOT [S2].Ecnt - ENV_END;
1162 not_end |= ch->SLOT [S1].Ecnt - ENV_END;
1163
1164 int CH_S0_OUT_1 = ch->S0_OUT [1];
1165
1166 GET_CURRENT_PHASE
1167 GET_CURRENT_LFO
1168
1169 if ( !not_end )
1170 return;
1171
1172 do
1173 {
1174 GET_ENV
1175 DO_FEEDBACK
1176
1177 int CH_OUTd;
1178 CH_OUTd = SINT( (in3 >> SIN_LBITS) & SIN_MASK, en3 ) +
1179 SINT( ((in1 + CH_S0_OUT_1) >> SIN_LBITS) & SIN_MASK, en1 ) +
1180 SINT( (in2 >> SIN_LBITS) & SIN_MASK, en2 );
1181
1182 DO_LIMIT
1183 UPDATE_PHASE_CYCLE
1184 UPDATE_ENV
1185 DO_OUTPUT_0
1186 }
1187 while ( --length );
1188 DO_OUTPUT_1
1189 UPDATE_PHASE
1190}
1191
1192void ym2612_update_chan7( struct tables_t* g, struct channel_* ch,
1193 short* buf, int length )
1194{
1195 int not_end = ch->SLOT [S3].Ecnt - ENV_END;
1196 not_end |= ch->SLOT [S0].Ecnt - ENV_END;
1197 not_end |= ch->SLOT [S2].Ecnt - ENV_END;
1198 not_end |= ch->SLOT [S1].Ecnt - ENV_END;
1199
1200 int CH_S0_OUT_1 = ch->S0_OUT [1];
1201
1202 GET_CURRENT_PHASE
1203 GET_CURRENT_LFO
1204
1205 if ( !not_end )
1206 return;
1207
1208 do
1209 {
1210 GET_ENV
1211 DO_FEEDBACK
1212
1213 int CH_OUTd;
1214 CH_OUTd = SINT( (in3 >> SIN_LBITS) & SIN_MASK, en3 ) +
1215 SINT( (in1 >> SIN_LBITS) & SIN_MASK, en1 ) +
1216 SINT( (in2 >> SIN_LBITS) & SIN_MASK, en2 ) + CH_S0_OUT_1;
1217
1218 DO_LIMIT
1219 UPDATE_PHASE_CYCLE
1220 UPDATE_ENV
1221 DO_OUTPUT_0
1222 }
1223 while ( --length );
1224 DO_OUTPUT_1
1225 UPDATE_PHASE
1226}
1227
1228static void (*UPDATE_CHAN[8])(struct tables_t* g, struct channel_* ch,
1229 short* buf, int length) =
1230{
1231 (void *)ym2612_update_chan0,
1232 (void *)ym2612_update_chan1,
1233 (void *)ym2612_update_chan2,
1234 (void *)ym2612_update_chan3,
1235 (void *)ym2612_update_chan4,
1236 (void *)ym2612_update_chan5,
1237 (void *)ym2612_update_chan6,
1238 (void *)ym2612_update_chan7
1239};
1240
1241void run_timer( struct Ym2612_Impl* impl, int length )
1242{
1243 int const step = 6;
1244 int remain = length;
1245 do
1246 {
1247 int n = step;
1248 if ( n > remain )
1249 n = remain;
1250 remain -= n;
1251
1252 int i = n * impl->YM2612.TimerBase;
1253 if (impl->YM2612.Mode & 1) // Timer A ON ?
1254 {
1255 // if ((impl->YM2612.TimerAcnt -= 14073) <= 0) // 13879=NTSC (old: 14475=NTSC 14586=PAL)
1256 if ((impl->YM2612.TimerAcnt -= i) <= 0)
1257 {
1258 // timer a overflow
1259
1260 impl->YM2612.Status |= (impl->YM2612.Mode & 0x04) >> 2;
1261 impl->YM2612.TimerAcnt += impl->YM2612.TimerAL;
1262
1263 if (impl->YM2612.Mode & 0x80)
1264 {
1265 KEY_ON( &impl->YM2612.CHANNEL [2], &impl->g, 0 );
1266 KEY_ON( &impl->YM2612.CHANNEL [2], &impl->g, 1 );
1267 KEY_ON( &impl->YM2612.CHANNEL [2], &impl->g, 2 );
1268 KEY_ON( &impl->YM2612.CHANNEL [2], &impl->g, 3 );
1269 }
1270 }
1271 }
1272
1273 if (impl->YM2612.Mode & 2) // Timer B ON ?
1274 {
1275 // if ((impl->YM2612.TimerBcnt -= 14073) <= 0) // 13879=NTSC (old: 14475=NTSC 14586=PAL)
1276 if ((impl->YM2612.TimerBcnt -= i) <= 0)
1277 {
1278 // timer b overflow
1279 impl->YM2612.Status |= (impl->YM2612.Mode & 0x08) >> 2;
1280 impl->YM2612.TimerBcnt += impl->YM2612.TimerBL;
1281 }
1282 }
1283 }
1284 while ( remain > 0 );
1285}
1286
1287void impl_run( struct Ym2612_Impl* impl, int pair_count, short out [] )
1288{
1289 if ( pair_count <= 0 )
1290 return;
1291
1292 if ( impl->YM2612.Mode & 3 )
1293 run_timer( impl, pair_count );
1294
1295 // Mise à jour des pas des compteurs-frequences s'ils ont ete modifies
1296
1297 int chi;
1298 for ( chi = 0; chi < ym2612_channel_count; chi++ )
1299 {
1300 struct channel_* ch = &impl->YM2612.CHANNEL [chi];
1301 if ( ch->SLOT [0].Finc != -1 )
1302 continue;
1303
1304 int i2 = 0;
1305 if ( chi == 2 && (impl->YM2612.Mode & 0x40) )
1306 i2 = 2;
1307
1308 int i;
1309 for ( i = 0; i < 4; i++ )
1310 {
1311 // static int seq [4] = { 2, 1, 3, 0 };
1312 // if ( i2 ) i2 = seq [i];
1313
1314 struct slot_t* sl = &ch->SLOT [i];
1315 int finc = impl->g.FINC_TAB [ch->FNUM [i2]] >> (7 - ch->FOCT [i2]);
1316 int ksr = ch->KC [i2] >> sl->KSR_S; // keycode attenuation
1317 sl->Finc = (finc + sl->DT [ch->KC [i2]]) * sl->MUL;
1318 if (sl->KSR != ksr) // si le KSR a change alors
1319 { // les differents taux pour l'enveloppe sont mis à jour
1320 sl->KSR = ksr;
1321
1322 sl->EincA = sl->AR [ksr];
1323 sl->EincD = sl->DR [ksr];
1324 sl->EincS = sl->SR [ksr];
1325 sl->EincR = sl->RR [ksr];
1326
1327 if (sl->Ecurp == ATTACK)
1328 {
1329 sl->Einc = sl->EincA;
1330 }
1331 else if (sl->Ecurp == DECAY)
1332 {
1333 sl->Einc = sl->EincD;
1334 }
1335 else if (sl->Ecnt < ENV_END)
1336 {
1337 if (sl->Ecurp == SUBSTAIN)
1338 sl->Einc = sl->EincS;
1339 else if (sl->Ecurp == RELEASE)
1340 sl->Einc = sl->EincR;
1341 }
1342 }
1343
1344 if ( i2 )
1345 i2 = (i2 ^ 2) ^ (i2 >> 1);
1346 }
1347 }
1348
1349 int i;
1350 for ( i = 0; i < ym2612_channel_count; i++ )
1351 {
1352 if ( !(impl->mute_mask & (1 << i)) && (i != 5 || !impl->YM2612.DAC) )
1353 UPDATE_CHAN [impl->YM2612.CHANNEL [i].ALGO]( &impl->g, &impl->YM2612.CHANNEL [i], out, pair_count );
1354 }
1355
1356 impl->g.LFOcnt += impl->g.LFOinc * pair_count;
1357}
1358
1359void Ym2612_run( struct Ym2612_Emu* this, int pair_count, short out [] ) { impl_run( &this->impl, pair_count, out ); }