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