workaround a problem with the harmattan gcc
[drnoksnes] / apu.cpp
1 /*
2  * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3  *
4  * (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and
5  *                           Jerremy Koot (jkoot@snes9x.com)
6  *
7  * Super FX C emulator code 
8  * (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and
9  *                           Gary Henderson.
10  * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
11  *
12  * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson.
13  * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_.
14  * C4 C code (c) Copyright 2001 Gary Henderson (gary.henderson@ntlworld.com).
15  *
16  * DOS port code contains the works of other authors. See headers in
17  * individual files.
18  *
19  * Snes9x homepage: http://www.snes9x.com
20  *
21  * Permission to use, copy, modify and distribute Snes9x in both binary and
22  * source form, for non-commercial purposes, is hereby granted without fee,
23  * providing that this license information and copyright notice appear with
24  * all copies and any derived work.
25  *
26  * This software is provided 'as-is', without any express or implied
27  * warranty. In no event shall the authors be held liable for any damages
28  * arising from the use of this software.
29  *
30  * Snes9x is freeware for PERSONAL USE only. Commercial users should
31  * seek permission of the copyright holders first. Commercial use includes
32  * charging money for Snes9x or software derived from Snes9x.
33  *
34  * The copyright holders request that bug fixes and improvements to the code
35  * should be forwarded to them so everyone can benefit from the modifications
36  * in future versions.
37  *
38  * Super NES and Super Nintendo Entertainment System are trademarks of
39  * Nintendo Co., Limited and its subsidiary companies.
40  */
41
42 #include "snes9x.h"
43 #include "spc700.h"
44 #include "apu.h"
45 #include "soundux.h"
46 #include "cpuexec.h"
47
48 //extern int NoiseFreq [32];
49 #ifdef DEBUGGER
50 void S9xTraceSoundDSP (const char *s, int i1 = 0, int i2 = 0, int i3 = 0,
51                        int i4 = 0, int i5 = 0, int i6 = 0, int i7 = 0);
52 #endif
53
54 #undef ABS
55 #define ABS(a) ((a) < 0 ? -(a) : (a))
56 #define ENVX_SHIFT 24
57
58
59 unsigned long AttackRate [16] = {
60         4100, 2600, 1500, 1000, 640, 380, 260, 160,
61         96, 64, 40, 24, 16, 10, 6, 1
62 };
63
64 unsigned long DecayRate [8] = {
65         1200, 740, 440, 290, 180, 110, 74, 37
66 };
67
68 unsigned long SustainRate [32] = {
69         /*~0*/0xFFFFFFFF, 38000, 28000, 24000, 19000, 14000, 12000, 9400,
70         7100, 5900, 4700, 3500, 2900, 2400, 1800, 1500,
71         1200, 880, 740, 590, 440, 370, 290, 220,
72         180, 150, 110, 92, 74, 55, 37, 18
73 };
74         
75 unsigned long IncreaseRate [32] = {
76         /*~0*/0xFFFFFFFF, 4100, 3100, 2600, 2000, 1500, 1300, 1000,
77         770, 640, 510, 380, 320, 260, 190, 160,
78         130, 96, 80, 64, 48, 40, 32, 24,
79         20, 16, 12, 10, 8, 6, 4, 2
80 };
81
82 unsigned long DecreaseRateExp [32] = {
83         /*~0*/0xFFFFFFFF, 38000, 28000, 24000, 19000, 14000, 12000, 9400,
84         7100, 5900, 4700, 3500, 2900, 2400, 1800, 1500,
85         1200, 880, 740, 590, 440, 370, 290, 220,
86         180, 150, 110, 92, 74, 55, 37, 18
87 };      
88
89 // precalculated env rates for S9xSetEnvRate
90 unsigned long AttackERate     [16][10];
91 unsigned long DecayERate       [8][10];
92 unsigned long SustainERate    [32][10];
93 unsigned long IncreaseERate   [32][10];
94 unsigned long DecreaseERateExp[32][10];
95 unsigned long KeyOffERate[10];
96
97
98 static inline void S9xSetEnvelopeRate (int channel, unsigned long rate, int direction, int target, unsigned int mode)
99 {
100     S9xSetEnvRate (&SoundData.channels [channel], rate, direction, target, mode);
101 }
102
103 static inline void S9xSetSoundADSR (int channel, int attack_ind, int decay_ind,
104                       int sustain_ind, int sustain_level, int release_rate)
105 {
106         int attack_rate = AttackRate [attack_ind];
107         int decay_rate = DecayRate [decay_ind];
108         int sustain_rate = SustainRate [sustain_ind];
109         
110         // Hack for ROMs that use a very short attack rate, key on a 
111         // channel, then switch to decay mode. e.g. Final Fantasy II.
112         if (attack_rate == 1)
113                 attack_rate = 0;
114
115         SoundData.channels[channel].env_ind_attack = attack_ind;
116     SoundData.channels[channel].env_ind_decay = decay_ind;
117     SoundData.channels[channel].env_ind_sustain = sustain_ind;
118
119         SoundData.channels[channel].attack_rate = attack_rate;
120     SoundData.channels[channel].decay_rate = decay_rate;
121     SoundData.channels[channel].sustain_rate = sustain_rate;
122     SoundData.channels[channel].release_rate = release_rate;
123     SoundData.channels[channel].sustain_level = sustain_level + 1;
124
125     switch (SoundData.channels[channel].state)
126     {
127     case SOUND_ATTACK:
128         S9xSetEnvelopeRate (channel, attack_rate, 1, 127, 0);
129         break;
130
131     case SOUND_DECAY:
132         S9xSetEnvelopeRate (channel, decay_rate, -1,
133                             (MAX_ENVELOPE_HEIGHT * (sustain_level + 1)) >> 3, 1<<28);
134         break;
135     case SOUND_SUSTAIN:
136         S9xSetEnvelopeRate (channel, sustain_rate, -1, 0, 2<<28);
137         break;
138     }
139 }
140
141 static inline void S9xSetSoundVolume (int channel, short volume_left, short volume_right)
142 {
143     Channel *ch = &SoundData.channels[channel];
144     if (!so.stereo)
145         volume_left = (ABS(volume_right) + ABS(volume_left)) / 2;
146
147     ch->volume_left = volume_left;
148     ch->volume_right = volume_right;
149     ch-> left_vol_level = (ch->envx * volume_left) / 128;
150     ch->right_vol_level = (ch->envx * volume_right) / 128;
151 }
152
153 static inline void S9xSetMasterVolume (short volume_left, short volume_right)
154 {
155     if (Settings.DisableMasterVolume)
156     {
157         SoundData.master_volume_left = 127;
158         SoundData.master_volume_right = 127;
159         SoundData.master_volume [0] = SoundData.master_volume [1] = 127;
160     }
161     else
162     {
163         if (!so.stereo)
164             volume_left = (ABS (volume_right) + ABS (volume_left)) / 2;
165         SoundData.master_volume_left = volume_left;
166         SoundData.master_volume_right = volume_right;
167         SoundData.master_volume [0] = volume_left;
168         SoundData.master_volume [1] = volume_right;
169     }
170 }
171
172 static inline void S9xSetEchoVolume (short volume_left, short volume_right)
173 {
174     if (!so.stereo)
175         volume_left = (ABS (volume_right) + ABS (volume_left)) / 2;
176     SoundData.echo_volume_left = volume_left;
177     SoundData.echo_volume_right = volume_right;
178     SoundData.echo_volume [0] = volume_left;
179     SoundData.echo_volume [1] = volume_right;
180 }
181
182 static inline void S9xSetEchoWriteEnable (uint8 byte)
183 {
184     SoundData.echo_write_enabled = byte;
185     S9xSetEchoDelay (APU.DSP [APU_EDL] & 15);
186 }
187
188 static inline void S9xSetFrequencyModulationEnable (uint8 byte)
189 {
190     SoundData.pitch_mod = byte & (0xFE);//~1;
191 }
192
193 static inline int S9xGetEnvelopeHeight (int channel)
194 {
195     if ((Settings.SoundEnvelopeHeightReading ||
196          SNESGameFixes.SoundEnvelopeHeightReading2) &&
197         SoundData.channels[channel].state != SOUND_SILENT &&
198         SoundData.channels[channel].state != SOUND_GAIN)
199     {
200         return (SoundData.channels[channel].envx);
201     }
202
203     //siren fix from XPP
204     if (SNESGameFixes.SoundEnvelopeHeightReading2 &&
205         SoundData.channels[channel].state != SOUND_SILENT)
206     {
207         return (SoundData.channels[channel].envx);
208     }
209
210     return (0);
211 }
212
213 static inline void S9xSetSoundHertz (int channel, int hertz)
214 {
215     SoundData.channels[channel].hertz = hertz;
216     S9xSetSoundFrequency (channel, hertz);
217 }
218
219 static inline void S9xSetSoundType (int channel, int type_of_sound)
220 {
221     SoundData.channels[channel].type = type_of_sound;
222 }
223
224 static inline bool8 S9xSetSoundMode (int channel, int mode)
225 {
226     Channel *ch = &SoundData.channels[channel];
227
228     switch (mode)
229     {
230     case MODE_RELEASE:
231         if (ch->mode != MODE_NONE)
232         {
233             ch->mode = MODE_RELEASE;
234             return (TRUE);
235         }
236         break;
237         
238     case MODE_DECREASE_LINEAR:
239     case MODE_DECREASE_EXPONENTIAL:
240     case MODE_GAIN:
241         if (ch->mode != MODE_RELEASE)
242         {
243             ch->mode = mode;
244             if (ch->state != SOUND_SILENT)
245                 ch->state = mode;
246
247             return (TRUE);
248         }
249         break;
250
251     case MODE_INCREASE_LINEAR:
252     case MODE_INCREASE_BENT_LINE:
253         if (ch->mode != MODE_RELEASE)
254         {
255             ch->mode = mode;
256             if (ch->state != SOUND_SILENT)
257                 ch->state = mode;
258
259             return (TRUE);
260         }
261         break;
262
263     case MODE_ADSR:
264         if (ch->mode == MODE_NONE || ch->mode == MODE_ADSR)
265         {
266             ch->mode = mode;
267             return (TRUE);
268         }
269     }
270
271     return (FALSE);
272 }
273
274 static inline void S9xPlaySample (int channel)
275 {
276     Channel *ch = &SoundData.channels[channel];
277     
278     ch->state = SOUND_SILENT;
279     ch->mode = MODE_NONE;
280     ch->envx = 0;
281     ch->envxx = 0;
282
283         ch->g_index=0;
284         ch->gaussian[0]=ch->gaussian[1]=ch->gaussian[2]=ch->gaussian[3]=0;
285
286     S9xFixEnvelope (channel,
287                     APU.DSP [APU_GAIN  + (channel << 4)], 
288                     APU.DSP [APU_ADSR1 + (channel << 4)],
289                     APU.DSP [APU_ADSR2 + (channel << 4)]);
290
291     ch->sample_number = APU.DSP [APU_SRCN + channel * 0x10];
292     if (APU.DSP [APU_NON] & (1 << channel))
293         ch->type = SOUND_NOISE;
294     else
295         ch->type = SOUND_SAMPLE;
296
297     S9xSetSoundFrequency (channel, ch->hertz);
298     ch->loop = FALSE;
299     ch->needs_decode = TRUE;
300     ch->last_block = FALSE;
301     ch->previous [0] = ch->previous[1] = 0;
302     ch->block_pointer = *S9xGetSampleAddress(ch->sample_number);
303     ch->sample_pointer = 0;
304     ch->env_error = 0;
305     ch->next_sample = 0;
306     ch->interpolate = 0;
307     ch->last_valid_header=0;
308     switch (ch->mode)
309     {
310     case MODE_ADSR:
311         if (ch->attack_rate == 0)
312         {
313             if (ch->decay_rate == 0 || ch->sustain_level == 8)
314             {
315                 ch->state = SOUND_SUSTAIN;
316                 ch->envx = (MAX_ENVELOPE_HEIGHT * ch->sustain_level) >> 3;
317                 S9xSetEnvRate (ch, ch->sustain_rate, -1, 0, 2<<28);
318             }
319             else
320             {
321                 ch->state = SOUND_DECAY;
322                 ch->envx = MAX_ENVELOPE_HEIGHT;
323                 S9xSetEnvRate (ch, ch->decay_rate, -1, 
324                                     (MAX_ENVELOPE_HEIGHT * ch->sustain_level) >> 3, 1<<28);
325             }
326             ch-> left_vol_level = (ch->envx * ch->volume_left) / 128;
327             ch->right_vol_level = (ch->envx * ch->volume_right) / 128;
328         }
329         else
330         {
331             ch->state = SOUND_ATTACK;
332             ch->envx = 0;
333             ch->left_vol_level = 0;
334             ch->right_vol_level = 0;
335             S9xSetEnvRate (ch, ch->attack_rate, 1, MAX_ENVELOPE_HEIGHT, 0);
336         }
337         ch->envxx = ch->envx << ENVX_SHIFT;
338         break;
339
340     case MODE_GAIN:
341         ch->state = SOUND_GAIN;
342         break;
343
344     case MODE_INCREASE_LINEAR:
345         ch->state = SOUND_INCREASE_LINEAR;
346         break;
347
348     case MODE_INCREASE_BENT_LINE:
349         ch->state = SOUND_INCREASE_BENT_LINE;
350         break;
351
352     case MODE_DECREASE_LINEAR:
353         ch->state = SOUND_DECREASE_LINEAR;
354         break;
355
356     case MODE_DECREASE_EXPONENTIAL:
357         ch->state = SOUND_DECREASE_EXPONENTIAL;
358         break;
359
360     default:
361         break;
362     }
363
364     S9xFixEnvelope (channel,
365                     APU.DSP [APU_GAIN  + (channel << 4)], 
366                     APU.DSP [APU_ADSR1 + (channel << 4)],
367                     APU.DSP [APU_ADSR2 + (channel << 4)]);
368 }
369
370 #ifdef ASM_SPC700
371 extern "C" uint32 Spc700JumpTab;
372 #endif
373
374 bool8 S9xInitAPU ()
375 {
376         // notaz
377         memset(&IAPU, 0, sizeof(IAPU));
378         IAPU.ExtraRAM = APU.ExtraRAM;
379 #ifdef ASM_SPC700
380         IAPU.asmJumpTab = &Spc700JumpTab;
381 #endif
382
383         IAPU.RAM = (uint8 *) malloc (0x10000);
384     IAPU.ShadowRAM = NULL;//(uint8 *) malloc (0x10000);
385     IAPU.CachedSamples = NULL;//(uint8 *) malloc (0x40000);
386     
387     if (!IAPU.RAM /*|| !IAPU.ShadowRAM || !IAPU.CachedSamples*/)
388     {
389         S9xDeinitAPU ();
390         return (FALSE);
391     }
392
393     return (TRUE);
394 }
395
396 void S9xDeinitAPU ()
397 {
398     if (IAPU.RAM)
399     {
400         free ((char *) IAPU.RAM);
401         IAPU.RAM = NULL;
402     }
403     if (IAPU.ShadowRAM)
404     {
405         free ((char *) IAPU.ShadowRAM);
406         IAPU.ShadowRAM = NULL;
407     }
408     if (IAPU.CachedSamples)
409     {
410         free ((char *) IAPU.CachedSamples);
411         IAPU.CachedSamples = NULL;
412     }
413 }
414
415 EXTERN_C uint8 APUROM [64];
416
417 void S9xResetAPU ()
418 {
419     memset (IAPU.RAM, Settings.APURAMInitialValue, 0x10000);
420     //memset (IAPU.ShadowRAM, Settings.APURAMInitialValue, 0x10000);
421     
422     //ZeroMemory (IAPU.CachedSamples, 0x40000);
423     ZeroMemory (APU.OutPorts, 4);
424     IAPU.DirectPage = IAPU.RAM;
425     memmove (&IAPU.RAM [0xffc0], APUROM, sizeof (APUROM));
426     memmove (APU.ExtraRAM, APUROM, sizeof (APUROM));
427     IAPU.PC = IAPU.RAM + IAPU.RAM [0xfffe] + (IAPU.RAM [0xffff] << 8);
428     CPU.APU_Cycles = 0;
429     IAPU.YA.W = 0;
430     IAPU.X = 0;
431     IAPU.S = 0xff;
432     IAPU.P = 0;
433     S9xAPUUnpackStatus ();
434     CPU.APU_APUExecuting = Settings.APUEnabled;
435 #ifdef SPC700_SHUTDOWN
436     IAPU.WaitAddress1 = NULL;
437     IAPU.WaitAddress2 = NULL;
438     IAPU.WaitCounter = 0;
439 #endif
440     APU.ShowROM = TRUE;
441     IAPU.RAM [0xf1] = 0x80;
442
443     int i;
444
445     for (i = 0; i < 3; i++)
446     {
447         APU.TimerEnabled [i] = FALSE;
448         APU.TimerValueWritten [i] = 0;
449         APU.TimerTarget [i] = 0;
450         APU.Timer [i] = 0;
451     }
452     for (int j = 0; j < 0x80; j++)
453         APU.DSP [j] = 0;
454
455     IAPU.TwoCycles = IAPU.OneCycle * 2;
456
457     for (i = 0; i < 256; i++)
458         S9xAPUCycles [i] = S9xAPUCycleLengths [i] * IAPU.OneCycle;
459
460     APU.DSP [APU_ENDX] = 0;
461     APU.DSP [APU_KOFF] = 0;
462     APU.DSP [APU_KON] = 0;
463     APU.DSP [APU_FLG] = APU_MUTE | APU_ECHO_DISABLED;
464     APU.KeyedChannels = 0;
465
466     S9xResetSound (TRUE);
467     S9xSetEchoEnable (0);
468 }
469
470 extern int framecpto;
471 void S9xSetAPUDSP (uint8 byte)
472 {
473     uint8 reg = IAPU.RAM [0xf2];
474         static uint8 KeyOn;
475         static uint8 KeyOnPrev;
476     int i;
477
478     switch (reg)
479     {
480     case APU_FLG:
481         if (byte & APU_SOFT_RESET)
482         {
483             APU.DSP [reg] = APU_MUTE | APU_ECHO_DISABLED | (byte & 0x1f);
484             APU.DSP [APU_ENDX] = 0;
485             APU.DSP [APU_KOFF] = 0;
486             APU.DSP [APU_KON] = 0;
487             S9xSetEchoWriteEnable (FALSE);
488 #ifdef DEBUGGER
489             if (Settings.TraceSoundDSP)
490                 S9xTraceSoundDSP ("[%d] DSP reset\n", ICPU.Scanline);
491 #endif
492             // Kill sound
493             S9xResetSound (FALSE);
494         }
495         else
496         {
497             S9xSetEchoWriteEnable (!(byte & APU_ECHO_DISABLED));
498             if (byte & APU_MUTE)
499             {
500 #ifdef DEBUGGER
501                 if (Settings.TraceSoundDSP)
502                     S9xTraceSoundDSP ("[%d] Mute sound\n", ICPU.Scanline);
503 #endif
504                 S9xSetSoundMute (TRUE);
505             }
506             else
507                 S9xSetSoundMute (FALSE);
508
509             SoundData.noise_hertz = NoiseFreq [byte & 0x1f];
510             for (i = 0; i < 8; i++)
511             {
512                 if (SoundData.channels [i].type == SOUND_NOISE)
513                     S9xSetSoundFrequency (i, SoundData.noise_hertz);
514             }
515         }
516         break;
517     case APU_NON:
518         if (byte != APU.DSP [APU_NON])
519         {
520 #ifdef DEBUGGER
521             if (Settings.TraceSoundDSP)
522                 S9xTraceSoundDSP ("[%d] Noise:", ICPU.Scanline);
523 #endif
524             uint8 mask = 1;
525             for (int c = 0; c < 8; c++, mask <<= 1)
526             {
527                 uint8 bit = byte & mask;
528                 if (bit)
529                 {
530 #ifdef DEBUGGER
531                     if (Settings.TraceSoundDSP)
532                     {
533                         if (APU.DSP [reg] & mask)
534                             S9xTraceSoundDSP ("%d,", c);
535                         else
536                             S9xTraceSoundDSP ("%d(on),", c);
537                     }
538 #endif
539                         S9xSetSoundType(c, SOUND_NOISE);
540                 }
541                 else
542                 {
543 #ifdef DEBUGGER
544                     if (Settings.TraceSoundDSP)
545                     {
546                         if (APU.DSP [reg] & mask)
547                             S9xTraceSoundDSP ("%d(off),", c);
548                     }
549 #endif
550                         S9xSetSoundType(c, SOUND_SAMPLE);
551                 }
552             }
553 #ifdef DEBUGGER
554             if (Settings.TraceSoundDSP)
555                 S9xTraceSoundDSP ("\n");
556 #endif
557         }
558         break;
559     case APU_MVOL_LEFT:
560         if (byte != APU.DSP [APU_MVOL_LEFT])
561         {
562 #ifdef DEBUGGER
563             if (Settings.TraceSoundDSP)
564                 S9xTraceSoundDSP ("[%d] Master volume left:%d\n", 
565                                   ICPU.Scanline, (signed char) byte);
566 #endif
567                 S9xSetMasterVolume ((signed char) byte,
568                                     (signed char) APU.DSP [APU_MVOL_RIGHT]);
569         }
570         break;
571     case APU_MVOL_RIGHT:
572         if (byte != APU.DSP [APU_MVOL_RIGHT])
573         {
574 #ifdef DEBUGGER
575             if (Settings.TraceSoundDSP)
576                 S9xTraceSoundDSP ("[%d] Master volume right:%d\n",
577                                   ICPU.Scanline, (signed char) byte);
578 #endif
579                 S9xSetMasterVolume ((signed char) APU.DSP [APU_MVOL_LEFT],
580                                     (signed char) byte);
581         }
582         break;
583     case APU_EVOL_LEFT:
584         if (byte != APU.DSP [APU_EVOL_LEFT])
585         {
586 #ifdef DEBUGGER
587             if (Settings.TraceSoundDSP)
588                 S9xTraceSoundDSP ("[%d] Echo volume left:%d\n",
589                                   ICPU.Scanline, (signed char) byte);
590 #endif
591                 S9xSetEchoVolume ((signed char) byte,
592                                   (signed char) APU.DSP [APU_EVOL_RIGHT]);
593         }
594         break;
595     case APU_EVOL_RIGHT:
596         if (byte != APU.DSP [APU_EVOL_RIGHT])
597         {
598 #ifdef DEBUGGER
599             if (Settings.TraceSoundDSP)
600                 S9xTraceSoundDSP ("[%d] Echo volume right:%d\n",
601                                   ICPU.Scanline, (signed char) byte);
602 #endif
603                 S9xSetEchoVolume ((signed char) APU.DSP [APU_EVOL_LEFT],
604                                   (signed char) byte);
605         }
606         break;
607     case APU_ENDX:
608 #ifdef DEBUGGER
609         if (Settings.TraceSoundDSP)
610             S9xTraceSoundDSP ("[%d] Reset ENDX\n", ICPU.Scanline);
611 #endif
612         byte = 0;
613         break;
614
615     case APU_KOFF:
616                 //              if (byte)
617         {
618             uint8 mask = 1;
619 #ifdef DEBUGGER
620             if (Settings.TraceSoundDSP)
621                 S9xTraceSoundDSP ("[%d] Key off:", ICPU.Scanline);
622 #endif
623             for (int c = 0; c < 8; c++, mask <<= 1)
624             {
625                 if ((byte & mask) != 0)
626                 {
627 #ifdef DEBUGGER
628
629                     if (Settings.TraceSoundDSP)
630                         S9xTraceSoundDSP ("%d,", c);
631 #endif              
632                     if (APU.KeyedChannels & mask)
633                     {
634                         {
635                                                         KeyOnPrev&=~mask;
636                             APU.KeyedChannels &= ~mask;
637                             APU.DSP [APU_KON] &= ~mask;
638                             //APU.DSP [APU_KOFF] |= mask;
639                             S9xSetSoundKeyOff (c);
640                         }
641                     }
642                 }
643                                 else if((KeyOnPrev&mask)!=0)
644                                 {
645                                         KeyOnPrev&=~mask;
646                                         APU.KeyedChannels |= mask;
647                                         //APU.DSP [APU_KON] |= mask;
648                                         APU.DSP [APU_KOFF] &= ~mask;
649                                         APU.DSP [APU_ENDX] &= ~mask;
650                                         S9xPlaySample (c);
651                                 }
652             }
653 #ifdef DEBUGGER
654             if (Settings.TraceSoundDSP)
655                 S9xTraceSoundDSP ("\n");
656 #endif
657         }
658                 //KeyOnPrev=0;
659         APU.DSP [APU_KOFF] = byte;
660         return;
661     case APU_KON:
662
663         if (byte)
664         {
665             uint8 mask = 1;
666 #ifdef DEBUGGER
667
668             if (Settings.TraceSoundDSP)
669                 S9xTraceSoundDSP ("[%d] Key on:", ICPU.Scanline);
670 #endif
671             for (int c = 0; c < 8; c++, mask <<= 1)
672             {
673                 if ((byte & mask) != 0)
674                 {
675 #ifdef DEBUGGER
676                     if (Settings.TraceSoundDSP)
677                         S9xTraceSoundDSP ("%d,", c);
678 #endif              
679                     // Pac-In-Time requires that channels can be key-on
680                     // regardeless of their current state.
681                                         if((APU.DSP [APU_KOFF] & mask) ==0)
682                                         {
683                                                 KeyOnPrev&=~mask;
684                     APU.KeyedChannels |= mask;
685                                                 //APU.DSP [APU_KON] |= mask;
686                                                 //APU.DSP [APU_KOFF] &= ~mask;
687                     APU.DSP [APU_ENDX] &= ~mask;
688                     S9xPlaySample (c);
689                 }
690                                         else KeyOn|=mask;
691                                 }
692             }
693 #ifdef DEBUGGER
694             if (Settings.TraceSoundDSP)
695                 S9xTraceSoundDSP ("\n");
696 #endif
697         }
698
699         return;
700         
701     case APU_VOL_LEFT + 0x00:
702     case APU_VOL_LEFT + 0x10:
703     case APU_VOL_LEFT + 0x20:
704     case APU_VOL_LEFT + 0x30:
705     case APU_VOL_LEFT + 0x40:
706     case APU_VOL_LEFT + 0x50:
707     case APU_VOL_LEFT + 0x60:
708     case APU_VOL_LEFT + 0x70:
709 // At Shin Megami Tensei suggestion 6/11/00
710 //      if (byte != APU.DSP [reg])
711         {
712 #ifdef DEBUGGER
713             if (Settings.TraceSoundDSP)
714                 S9xTraceSoundDSP ("[%d] %d volume left: %d\n", 
715                                   ICPU.Scanline, reg>>4, (signed char) byte);
716 #endif
717                 S9xSetSoundVolume (reg >> 4, (signed char) byte,
718                                    (signed char) APU.DSP [reg + 1]);
719         }
720         break;
721     case APU_VOL_RIGHT + 0x00:
722     case APU_VOL_RIGHT + 0x10:
723     case APU_VOL_RIGHT + 0x20:
724     case APU_VOL_RIGHT + 0x30:
725     case APU_VOL_RIGHT + 0x40:
726     case APU_VOL_RIGHT + 0x50:
727     case APU_VOL_RIGHT + 0x60:
728     case APU_VOL_RIGHT + 0x70:
729 // At Shin Megami Tensei suggestion 6/11/00
730 //      if (byte != APU.DSP [reg])
731         {
732 #ifdef DEBUGGER
733             if (Settings.TraceSoundDSP)
734                 S9xTraceSoundDSP ("[%d] %d volume right: %d\n", 
735                                   ICPU.Scanline, reg >>4, (signed char) byte);
736 #endif
737                 S9xSetSoundVolume (reg >> 4, (signed char) APU.DSP [reg - 1],
738                                    (signed char) byte);
739         }
740         break;
741
742     case APU_P_LOW + 0x00:
743     case APU_P_LOW + 0x10:
744     case APU_P_LOW + 0x20:
745     case APU_P_LOW + 0x30:
746     case APU_P_LOW + 0x40:
747     case APU_P_LOW + 0x50:
748     case APU_P_LOW + 0x60:
749     case APU_P_LOW + 0x70:
750 #ifdef DEBUGGER
751         if (Settings.TraceSoundDSP)
752             S9xTraceSoundDSP ("[%d] %d freq low: %d\n",
753                               ICPU.Scanline, reg>>4, byte);
754 #endif
755             S9xSetSoundHertz (reg >> 4, (((byte + (APU.DSP [reg + 1] << 8)) & FREQUENCY_MASK) * 32000) >> 12);
756         break;
757
758     case APU_P_HIGH + 0x00:
759     case APU_P_HIGH + 0x10:
760     case APU_P_HIGH + 0x20:
761     case APU_P_HIGH + 0x30:
762     case APU_P_HIGH + 0x40:
763     case APU_P_HIGH + 0x50:
764     case APU_P_HIGH + 0x60:
765     case APU_P_HIGH + 0x70:
766 #ifdef DEBUGGER
767         if (Settings.TraceSoundDSP)
768             S9xTraceSoundDSP ("[%d] %d freq high: %d\n",
769                               ICPU.Scanline, reg>>4, byte);
770 #endif
771             S9xSetSoundHertz (reg >> 4, 
772                         (((byte << 8) + APU.DSP [reg - 1]) & FREQUENCY_MASK) * 8);
773         break;
774
775     case APU_SRCN + 0x00:
776     case APU_SRCN + 0x10:
777     case APU_SRCN + 0x20:
778     case APU_SRCN + 0x30:
779     case APU_SRCN + 0x40:
780     case APU_SRCN + 0x50:
781     case APU_SRCN + 0x60:
782     case APU_SRCN + 0x70:
783         if (byte != APU.DSP [reg])
784         {
785 #ifdef DEBUGGER
786             if (Settings.TraceSoundDSP)
787                 S9xTraceSoundDSP ("[%d] %d sample number: %d\n",
788                                   ICPU.Scanline, reg>>4, byte);
789 #endif
790             //S9xSetSoundSample (reg >> 4, byte); // notaz: seems to be unused?
791         }
792         break;
793         
794     case APU_ADSR1 + 0x00:
795     case APU_ADSR1 + 0x10:
796     case APU_ADSR1 + 0x20:
797     case APU_ADSR1 + 0x30:
798     case APU_ADSR1 + 0x40:
799     case APU_ADSR1 + 0x50:
800     case APU_ADSR1 + 0x60:
801     case APU_ADSR1 + 0x70:
802         if (byte != APU.DSP [reg])
803         {
804 #ifdef DEBUGGER
805             if (Settings.TraceSoundDSP)
806                 S9xTraceSoundDSP ("[%d] %d adsr1: %02x\n",
807                                   ICPU.Scanline, reg>>4, byte);
808 #endif
809             {
810                 S9xFixEnvelope (reg >> 4, APU.DSP [reg + 2], byte, 
811                              APU.DSP [reg + 1]);
812             }
813         }
814         break;
815
816     case APU_ADSR2 + 0x00:
817     case APU_ADSR2 + 0x10:
818     case APU_ADSR2 + 0x20:
819     case APU_ADSR2 + 0x30:
820     case APU_ADSR2 + 0x40:
821     case APU_ADSR2 + 0x50:
822     case APU_ADSR2 + 0x60:
823     case APU_ADSR2 + 0x70:
824         if (byte != APU.DSP [reg])
825         {
826 #ifdef DEBUGGER
827             if (Settings.TraceSoundDSP)
828                 S9xTraceSoundDSP ("[%d] %d adsr2: %02x\n", 
829                                   ICPU.Scanline, reg>>4, byte);
830 #endif
831             {
832                 S9xFixEnvelope (reg >> 4, APU.DSP [reg + 1], APU.DSP [reg - 1],
833                              byte);
834             }
835         }
836         break;
837
838     case APU_GAIN + 0x00:
839     case APU_GAIN + 0x10:
840     case APU_GAIN + 0x20:
841     case APU_GAIN + 0x30:
842     case APU_GAIN + 0x40:
843     case APU_GAIN + 0x50:
844     case APU_GAIN + 0x60:
845     case APU_GAIN + 0x70:
846         if (byte != APU.DSP [reg])
847         {
848 #ifdef DEBUGGER
849             if (Settings.TraceSoundDSP)
850                 S9xTraceSoundDSP ("[%d] %d gain: %02x\n",
851                                   ICPU.Scanline, reg>>4, byte);
852 #endif
853             {
854                 S9xFixEnvelope (reg >> 4, byte, APU.DSP [reg - 2],
855                              APU.DSP [reg - 1]);
856             }
857         }
858         break;
859
860     case APU_ENVX + 0x00:
861     case APU_ENVX + 0x10:
862     case APU_ENVX + 0x20:
863     case APU_ENVX + 0x30:
864     case APU_ENVX + 0x40:
865     case APU_ENVX + 0x50:
866     case APU_ENVX + 0x60:
867     case APU_ENVX + 0x70:
868         break;
869
870     case APU_OUTX + 0x00:
871     case APU_OUTX + 0x10:
872     case APU_OUTX + 0x20:
873     case APU_OUTX + 0x30:
874     case APU_OUTX + 0x40:
875     case APU_OUTX + 0x50:
876     case APU_OUTX + 0x60:
877     case APU_OUTX + 0x70:
878         break;
879     
880     case APU_DIR:
881 #ifdef DEBUGGER
882         if (Settings.TraceSoundDSP)
883             S9xTraceSoundDSP ("[%d] Sample directory to: %02x\n",
884                               ICPU.Scanline, byte);
885 #endif
886         break;
887
888     case APU_PMON:
889         if (byte != APU.DSP [APU_PMON])
890         {
891 #ifdef DEBUGGER
892             if (Settings.TraceSoundDSP)
893             {
894                 S9xTraceSoundDSP ("[%d] FreqMod:", ICPU.Scanline);
895                 uint8 mask = 1;
896                 for (int c = 0; c < 8; c++, mask <<= 1)
897                 {
898                     if (byte & mask)
899                     {
900                         if (APU.DSP [reg] & mask)
901                             S9xTraceSoundDSP ("%d", c);
902                         else
903                             S9xTraceSoundDSP ("%d(on),", c);
904                     }
905                     else
906                     {
907                         if (APU.DSP [reg] & mask)
908                             S9xTraceSoundDSP ("%d(off),", c);
909                     }
910                 }
911                 S9xTraceSoundDSP ("\n");
912             }
913 #endif
914                 S9xSetFrequencyModulationEnable (byte);
915         }
916         break;
917
918     case APU_EON:
919         if (byte != APU.DSP [APU_EON])
920         {
921 #ifdef DEBUGGER
922             if (Settings.TraceSoundDSP)
923             {
924                 S9xTraceSoundDSP ("[%d] Echo:", ICPU.Scanline);
925                 uint8 mask = 1;
926                 for (int c = 0; c < 8; c++, mask <<= 1)
927                 {
928                     if (byte & mask)
929                     {
930                         if (APU.DSP [reg] & mask)
931                             S9xTraceSoundDSP ("%d", c);
932                         else
933                             S9xTraceSoundDSP ("%d(on),", c);
934                     }
935                     else
936                     {
937                         if (APU.DSP [reg] & mask)
938                             S9xTraceSoundDSP ("%d(off),", c);
939                     }
940                 }
941                 S9xTraceSoundDSP ("\n");
942             }
943 #endif
944                 S9xSetEchoEnable (byte);
945         }
946         break;
947
948     case APU_EFB:
949         S9xSetEchoFeedback ((signed char) byte);
950         break;
951
952     case APU_ESA:
953         break;
954
955     case APU_EDL:
956         S9xSetEchoDelay (byte & 0xf);
957         break;
958
959     case APU_C0:
960     case APU_C1:
961     case APU_C2:
962     case APU_C3:
963     case APU_C4:
964     case APU_C5:
965     case APU_C6:
966     case APU_C7:
967         S9xSetFilterCoefficient (reg >> 4, (signed char) byte);
968         break;
969     default:
970 // XXX
971 //printf ("Write %02x to unknown APU register %02x\n", byte, reg);
972         break;
973     }
974
975         KeyOnPrev|=KeyOn;
976         KeyOn=0;
977         
978     if (reg < 0x80)
979         APU.DSP [reg] = byte;
980 }
981
982 void S9xFixEnvelope (int channel, uint8 gain, uint8 adsr1, uint8 adsr2)
983 {
984     if (adsr1 & 0x80)
985     {
986                 // ADSR mode
987                 
988                 // XXX: can DSP be switched to ADSR mode directly from GAIN/INCREASE/
989                 // DECREASE mode? And if so, what stage of the sequence does it start
990                 // at?
991                 if (S9xSetSoundMode (channel, MODE_ADSR))
992                 {
993                         S9xSetSoundADSR (channel, adsr1 & 0xf, (adsr1 >> 4) & 7, adsr2 & 0x1f, (adsr2 >> 5) & 7, 8);
994                 }
995     }
996     else
997     {
998                 // Gain mode
999                 if ((gain & 0x80) == 0)
1000                 {
1001                         if (S9xSetSoundMode (channel, MODE_GAIN))
1002                         {
1003                         S9xSetEnvelopeRate (channel, 0, 0, gain & 0x7f, 0);
1004                         S9xSetEnvelopeHeight (channel, gain & 0x7f);
1005                         }
1006                 }
1007                 else
1008                 {
1009                         
1010                         if (gain & 0x40)
1011                         {
1012                                 // Increase mode
1013                                 if (S9xSetSoundMode (channel, (gain & 0x20) ?
1014                                                           MODE_INCREASE_BENT_LINE :
1015                                                           MODE_INCREASE_LINEAR))
1016                                 {
1017                                         S9xSetEnvelopeRate (channel, IncreaseRate [gain & 0x1f], 1, 127, (3<<28)|gain);
1018                                 }
1019                         }
1020                         else
1021                         {
1022                                 if(gain & 0x20) {
1023                                         if (S9xSetSoundMode (channel, MODE_DECREASE_EXPONENTIAL))
1024                                                 S9xSetEnvelopeRate (channel, DecreaseRateExp [gain & 0x1f] / 2, -1, 0, (4<<28)|gain);
1025                                 } else {
1026                                         if (S9xSetSoundMode (channel, MODE_DECREASE_LINEAR))
1027                                                 S9xSetEnvelopeRate (channel, IncreaseRate [gain & 0x1f], -1, 0, (3<<28)|gain);
1028                                 }
1029                         }
1030                 }
1031     }
1032 }
1033
1034 void S9xSetAPUControl (uint8 byte)
1035 {
1036 //if (byte & 0x40)
1037 //printf ("*** Special SPC700 timing enabled\n");
1038     if ((byte & 1) != 0 && !APU.TimerEnabled [0])
1039     {
1040         APU.Timer [0] = 0;
1041         IAPU.RAM [0xfd] = 0;
1042         if ((APU.TimerTarget [0] = IAPU.RAM [0xfa]) == 0)
1043             APU.TimerTarget [0] = 0x100;
1044     }
1045     if ((byte & 2) != 0 && !APU.TimerEnabled [1])
1046     {
1047         APU.Timer [1] = 0;
1048         IAPU.RAM [0xfe] = 0;
1049         if ((APU.TimerTarget [1] = IAPU.RAM [0xfb]) == 0)
1050             APU.TimerTarget [1] = 0x100;
1051     }
1052     if ((byte & 4) != 0 && !APU.TimerEnabled [2])
1053     {
1054         APU.Timer [2] = 0;
1055         IAPU.RAM [0xff] = 0;
1056         if ((APU.TimerTarget [2] = IAPU.RAM [0xfc]) == 0)
1057             APU.TimerTarget [2] = 0x100;
1058     }
1059     APU.TimerEnabled [0] = byte & 1;
1060     APU.TimerEnabled [1] = (byte & 2) >> 1;
1061     APU.TimerEnabled [2] = (byte & 4) >> 2;
1062
1063     if (byte & 0x10)
1064         IAPU.RAM [0xF4] = IAPU.RAM [0xF5] = 0;
1065
1066     if (byte & 0x20)
1067         IAPU.RAM [0xF6] = IAPU.RAM [0xF7] = 0;
1068
1069     if (byte & 0x80)
1070     {
1071         if (!APU.ShowROM)
1072         {
1073             memmove (&IAPU.RAM [0xffc0], APUROM, sizeof (APUROM));
1074             APU.ShowROM = TRUE;
1075         }
1076     }
1077     else
1078     {
1079         if (APU.ShowROM)
1080         {
1081             APU.ShowROM = FALSE;
1082             memmove (&IAPU.RAM [0xffc0], APU.ExtraRAM, sizeof (APUROM));
1083         }
1084     }
1085     IAPU.RAM [0xf1] = byte;
1086 }
1087
1088 void S9xSetAPUTimer (uint16 Address, uint8 byte)
1089 {
1090     IAPU.RAM [Address] = byte;
1091
1092     switch (Address)
1093     {
1094     case 0xfa:
1095         if ((APU.TimerTarget [0] = IAPU.RAM [0xfa]) == 0)
1096             APU.TimerTarget [0] = 0x100;
1097         APU.TimerValueWritten [0] = TRUE;
1098         break;
1099     case 0xfb:
1100         if ((APU.TimerTarget [1] = IAPU.RAM [0xfb]) == 0)
1101             APU.TimerTarget [1] = 0x100;
1102         APU.TimerValueWritten [1] = TRUE;
1103         break;
1104     case 0xfc:
1105         if ((APU.TimerTarget [2] = IAPU.RAM [0xfc]) == 0)
1106             APU.TimerTarget [2] = 0x100;
1107         APU.TimerValueWritten [2] = TRUE;
1108         break;
1109     }
1110 }
1111
1112 uint8 S9xGetAPUDSP ()
1113 {
1114     uint8 reg = IAPU.RAM [0xf2] & 0x7f;
1115     uint8 byte = APU.DSP [reg];
1116
1117     switch (reg)
1118     {
1119     case APU_KON:
1120         break;
1121     case APU_KOFF:
1122         break;
1123     case APU_OUTX + 0x00:
1124     case APU_OUTX + 0x10:
1125     case APU_OUTX + 0x20:
1126     case APU_OUTX + 0x30:
1127     case APU_OUTX + 0x40:
1128     case APU_OUTX + 0x50:
1129     case APU_OUTX + 0x60:
1130     case APU_OUTX + 0x70:
1131         if (SoundData.channels [reg >> 4].state == SOUND_SILENT)
1132             return (0);
1133         return ((SoundData.channels [reg >> 4].sample >> 8) |
1134                 (SoundData.channels [reg >> 4].sample & 0xff));
1135
1136     case APU_ENVX + 0x00:
1137     case APU_ENVX + 0x10:
1138     case APU_ENVX + 0x20:
1139     case APU_ENVX + 0x30:
1140     case APU_ENVX + 0x40:
1141     case APU_ENVX + 0x50:
1142     case APU_ENVX + 0x60:
1143     case APU_ENVX + 0x70:
1144                 return 0;
1145 //              return ((uint8) S9xGetEnvelopeHeight (reg >> 4));
1146
1147     case APU_ENDX:
1148 // To fix speech in Magical Drop 2 6/11/00
1149 //      APU.DSP [APU_ENDX] = 0;
1150         break;
1151     default:
1152         break;
1153     }
1154     return (byte);
1155 }