2 * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
4 * (c) Copyright 1996 - 2001 Gary Henderson (gary.henderson@ntlworld.com) and
5 * Jerremy Koot (jkoot@snes9x.com)
7 * Super FX C emulator code
8 * (c) Copyright 1997 - 1999 Ivar (ivar@snes9x.com) and
10 * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_.
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).
16 * DOS port code contains the works of other authors. See headers in
19 * Snes9x homepage: http://www.snes9x.com
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.
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.
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.
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
38 * Super NES and Super Nintendo Entertainment System are trademarks of
39 * Nintendo Co., Limited and its subsidiary companies.
48 /* For note-triggered SPC dump support */
49 //#include "snapshot.h"
51 //extern int NoiseFreq [32];
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);
58 #define ABS(a) ((a) < 0 ? -(a) : (a))
62 unsigned long AttackRate [16] = {
63 4100, 2600, 1500, 1000, 640, 380, 260, 160,
64 96, 64, 40, 24, 16, 10, 6, 1
67 unsigned long DecayRate [8] = {
68 1200, 740, 440, 290, 180, 110, 74, 37
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
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
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
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];
101 static inline void S9xSetEnvelopeRate (int channel, unsigned long rate, int direction, int target, unsigned int mode)
103 S9xSetEnvRate (&SoundData.channels [channel], rate, direction, target, mode);
106 static inline void S9xSetSoundADSR (int channel, int attack_ind, int decay_ind,
107 int sustain_ind, int sustain_level, int release_rate)
109 int attack_rate = AttackRate [attack_ind];
110 int decay_rate = DecayRate [decay_ind];
111 int sustain_rate = SustainRate [sustain_ind];
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)
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;
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;
128 switch (SoundData.channels[channel].state)
131 S9xSetEnvelopeRate (channel, attack_rate, 1, 127, 0);
135 S9xSetEnvelopeRate (channel, decay_rate, -1,
136 (MAX_ENVELOPE_HEIGHT * (sustain_level + 1)) >> 3, 1<<28);
139 S9xSetEnvelopeRate (channel, sustain_rate, -1, 0, 2<<28);
144 static inline void S9xSetSoundVolume (int channel, short volume_left, short volume_right)
146 Channel *ch = &SoundData.channels[channel];
148 volume_left = (ABS(volume_right) + ABS(volume_left)) / 2;
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;
156 static inline void S9xSetMasterVolume (short volume_left, short volume_right)
158 if (Settings.DisableMasterVolume)
160 SoundData.master_volume_left = 127;
161 SoundData.master_volume_right = 127;
162 SoundData.master_volume [0] = SoundData.master_volume [1] = 127;
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;
175 static inline void S9xSetEchoVolume (short volume_left, short volume_right)
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;
185 static inline void S9xSetEchoWriteEnable (uint8 byte)
187 SoundData.echo_write_enabled = byte;
188 S9xSetEchoDelay (APU.DSP [APU_EDL] & 15);
191 static inline void S9xSetFrequencyModulationEnable (uint8 byte)
193 SoundData.pitch_mod = byte & (0xFE);//~1;
196 static inline int S9xGetEnvelopeHeight (int channel)
198 if ((Settings.SoundEnvelopeHeightReading ||
199 SNESGameFixes.SoundEnvelopeHeightReading2) &&
200 SoundData.channels[channel].state != SOUND_SILENT &&
201 SoundData.channels[channel].state != SOUND_GAIN)
203 return (SoundData.channels[channel].envx);
207 if (SNESGameFixes.SoundEnvelopeHeightReading2 &&
208 SoundData.channels[channel].state != SOUND_SILENT)
210 return (SoundData.channels[channel].envx);
216 static inline void S9xSetSoundHertz (int channel, int hertz)
218 SoundData.channels[channel].hertz = hertz;
219 S9xSetSoundFrequency (channel, hertz);
222 static inline void S9xSetSoundType (int channel, int type_of_sound)
224 SoundData.channels[channel].type = type_of_sound;
227 static inline bool8 S9xSetSoundMode (int channel, int mode)
229 Channel *ch = &SoundData.channels[channel];
234 if (ch->mode != MODE_NONE)
236 ch->mode = MODE_RELEASE;
241 case MODE_DECREASE_LINEAR:
242 case MODE_DECREASE_EXPONENTIAL:
244 if (ch->mode != MODE_RELEASE)
247 if (ch->state != SOUND_SILENT)
254 case MODE_INCREASE_LINEAR:
255 case MODE_INCREASE_BENT_LINE:
256 if (ch->mode != MODE_RELEASE)
259 if (ch->state != SOUND_SILENT)
267 if (ch->mode == MODE_NONE || ch->mode == MODE_ADSR)
277 static inline void S9xPlaySample (int channel)
279 Channel *ch = &SoundData.channels[channel];
281 ch->state = SOUND_SILENT;
282 ch->mode = MODE_NONE;
287 ch->gaussian[0]=ch->gaussian[1]=ch->gaussian[2]=ch->gaussian[3]=0;
289 S9xFixEnvelope (channel,
290 APU.DSP [APU_GAIN + (channel << 4)],
291 APU.DSP [APU_ADSR1 + (channel << 4)],
292 APU.DSP [APU_ADSR2 + (channel << 4)]);
294 ch->sample_number = APU.DSP [APU_SRCN + channel * 0x10];
295 if (APU.DSP [APU_NON] & (1 << channel))
296 ch->type = SOUND_NOISE;
298 ch->type = SOUND_SAMPLE;
300 S9xSetSoundFrequency (channel, ch->hertz);
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;
310 ch->last_valid_header=0;
314 if (ch->attack_rate == 0)
316 if (ch->decay_rate == 0 || ch->sustain_level == 8)
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);
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);
329 ch-> left_vol_level = (ch->envx * ch->volume_left) / 128;
330 ch->right_vol_level = (ch->envx * ch->volume_right) / 128;
334 ch->state = SOUND_ATTACK;
336 ch->left_vol_level = 0;
337 ch->right_vol_level = 0;
338 S9xSetEnvRate (ch, ch->attack_rate, 1, MAX_ENVELOPE_HEIGHT, 0);
340 ch->envxx = ch->envx << ENVX_SHIFT;
344 ch->state = SOUND_GAIN;
347 case MODE_INCREASE_LINEAR:
348 ch->state = SOUND_INCREASE_LINEAR;
351 case MODE_INCREASE_BENT_LINE:
352 ch->state = SOUND_INCREASE_BENT_LINE;
355 case MODE_DECREASE_LINEAR:
356 ch->state = SOUND_DECREASE_LINEAR;
359 case MODE_DECREASE_EXPONENTIAL:
360 ch->state = SOUND_DECREASE_EXPONENTIAL;
367 S9xFixEnvelope (channel,
368 APU.DSP [APU_GAIN + (channel << 4)],
369 APU.DSP [APU_ADSR1 + (channel << 4)],
370 APU.DSP [APU_ADSR2 + (channel << 4)]);
374 extern "C" uint32 Spc700JumpTab;
380 memset(&IAPU, 0, sizeof(IAPU));
381 IAPU.ExtraRAM = APU.ExtraRAM;
383 IAPU.asmJumpTab = &Spc700JumpTab;
386 IAPU.RAM = (uint8 *) malloc (0x10000);
387 IAPU.ShadowRAM = NULL;//(uint8 *) malloc (0x10000);
388 IAPU.CachedSamples = NULL;//(uint8 *) malloc (0x40000);
390 if (!IAPU.RAM /*|| !IAPU.ShadowRAM || !IAPU.CachedSamples*/)
403 free ((char *) IAPU.RAM);
408 free ((char *) IAPU.ShadowRAM);
409 IAPU.ShadowRAM = NULL;
411 if (IAPU.CachedSamples)
413 free ((char *) IAPU.CachedSamples);
414 IAPU.CachedSamples = NULL;
418 EXTERN_C uint8 APUROM [64];
422 // Settings.APUEnabled = Settings.NextAPUEnabled;
424 memset (IAPU.RAM, Settings.APURAMInitialValue, 0x10000);
425 //memset (IAPU.ShadowRAM, Settings.APURAMInitialValue, 0x10000);
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);
438 S9xAPUUnpackStatus ();
439 CPU.APU_APUExecuting = Settings.APUEnabled;
440 #ifdef SPC700_SHUTDOWN
441 IAPU.WaitAddress1 = NULL;
442 IAPU.WaitAddress2 = NULL;
443 IAPU.WaitCounter = 0;
446 IAPU.RAM [0xf1] = 0x80;
450 for (i = 0; i < 3; i++)
452 APU.TimerEnabled [i] = FALSE;
453 APU.TimerValueWritten [i] = 0;
454 APU.TimerTarget [i] = 0;
457 for (int j = 0; j < 0x80; j++)
460 IAPU.TwoCycles = IAPU.OneCycle * 2;
462 for (i = 0; i < 256; i++)
463 S9xAPUCycles [i] = S9xAPUCycleLengths [i] * IAPU.OneCycle;
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;
471 S9xResetSound (TRUE);
472 S9xSetEchoEnable (0);
475 extern int framecpto;
476 void S9xSetAPUDSP (uint8 byte)
478 uint8 reg = IAPU.RAM [0xf2];
480 static uint8 KeyOnPrev;
486 sprintf(str,"fr : %d\nwrite dsp %d\ncpu cycle=%d pc=%04X",framecpto,byte,CPU.Cycles,CPU.PC-CPU.PCBase);
491 //extern uint8 spc_dump_dsp[0x100];
493 //spc_dump_dsp[reg] = byte;
498 if (byte & APU_SOFT_RESET)
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);
506 if (Settings.TraceSoundDSP)
507 S9xTraceSoundDSP ("[%d] DSP reset\n", ICPU.Scanline);
510 S9xResetSound (FALSE);
514 S9xSetEchoWriteEnable (!(byte & APU_ECHO_DISABLED));
518 if (Settings.TraceSoundDSP)
519 S9xTraceSoundDSP ("[%d] Mute sound\n", ICPU.Scanline);
521 S9xSetSoundMute (TRUE);
524 S9xSetSoundMute (FALSE);
526 SoundData.noise_hertz = NoiseFreq [byte & 0x1f];
527 for (i = 0; i < 8; i++)
529 if (SoundData.channels [i].type == SOUND_NOISE)
530 S9xSetSoundFrequency (i, SoundData.noise_hertz);
535 if (byte != APU.DSP [APU_NON])
538 if (Settings.TraceSoundDSP)
539 S9xTraceSoundDSP ("[%d] Noise:", ICPU.Scanline);
542 for (int c = 0; c < 8; c++, mask <<= 1)
549 if (Settings.TraceSoundDSP)
551 if (APU.DSP [reg] & mask)
552 S9xTraceSoundDSP ("%d,", c);
554 S9xTraceSoundDSP ("%d(on),", c);
562 if (Settings.TraceSoundDSP)
564 if (APU.DSP [reg] & mask)
565 S9xTraceSoundDSP ("%d(off),", c);
569 S9xSetSoundType (c, type);
572 if (Settings.TraceSoundDSP)
573 S9xTraceSoundDSP ("\n");
578 if (byte != APU.DSP [APU_MVOL_LEFT])
581 if (Settings.TraceSoundDSP)
582 S9xTraceSoundDSP ("[%d] Master volume left:%d\n",
583 ICPU.Scanline, (signed char) byte);
585 S9xSetMasterVolume ((signed char) byte,
586 (signed char) APU.DSP [APU_MVOL_RIGHT]);
590 if (byte != APU.DSP [APU_MVOL_RIGHT])
593 if (Settings.TraceSoundDSP)
594 S9xTraceSoundDSP ("[%d] Master volume right:%d\n",
595 ICPU.Scanline, (signed char) byte);
597 S9xSetMasterVolume ((signed char) APU.DSP [APU_MVOL_LEFT],
602 if (byte != APU.DSP [APU_EVOL_LEFT])
605 if (Settings.TraceSoundDSP)
606 S9xTraceSoundDSP ("[%d] Echo volume left:%d\n",
607 ICPU.Scanline, (signed char) byte);
609 S9xSetEchoVolume ((signed char) byte,
610 (signed char) APU.DSP [APU_EVOL_RIGHT]);
614 if (byte != APU.DSP [APU_EVOL_RIGHT])
617 if (Settings.TraceSoundDSP)
618 S9xTraceSoundDSP ("[%d] Echo volume right:%d\n",
619 ICPU.Scanline, (signed char) byte);
621 S9xSetEchoVolume ((signed char) APU.DSP [APU_EVOL_LEFT],
627 if (Settings.TraceSoundDSP)
628 S9xTraceSoundDSP ("[%d] Reset ENDX\n", ICPU.Scanline);
638 if (Settings.TraceSoundDSP)
639 S9xTraceSoundDSP ("[%d] Key off:", ICPU.Scanline);
641 for (int c = 0; c < 8; c++, mask <<= 1)
643 if ((byte & mask) != 0)
647 if (Settings.TraceSoundDSP)
648 S9xTraceSoundDSP ("%d,", c);
650 if (APU.KeyedChannels & mask)
654 APU.KeyedChannels &= ~mask;
655 APU.DSP [APU_KON] &= ~mask;
656 //APU.DSP [APU_KOFF] |= mask;
657 S9xSetSoundKeyOff (c);
661 else if((KeyOnPrev&mask)!=0)
664 APU.KeyedChannels |= mask;
665 //APU.DSP [APU_KON] |= mask;
666 APU.DSP [APU_KOFF] &= ~mask;
667 APU.DSP [APU_ENDX] &= ~mask;
672 if (Settings.TraceSoundDSP)
673 S9xTraceSoundDSP ("\n");
677 APU.DSP [APU_KOFF] = byte;
686 if (Settings.TraceSoundDSP)
687 S9xTraceSoundDSP ("[%d] Key on:", ICPU.Scanline);
689 for (int c = 0; c < 8; c++, mask <<= 1)
691 if ((byte & mask) != 0)
694 if (Settings.TraceSoundDSP)
695 S9xTraceSoundDSP ("%d,", c);
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)
702 APU.KeyedChannels |= mask;
703 //APU.DSP [APU_KON] |= mask;
704 //APU.DSP [APU_KOFF] &= ~mask;
705 APU.DSP [APU_ENDX] &= ~mask;
712 if (Settings.TraceSoundDSP)
713 S9xTraceSoundDSP ("\n");
716 //spc_is_dumping_temp = byte;
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])
731 if (Settings.TraceSoundDSP)
732 S9xTraceSoundDSP ("[%d] %d volume left: %d\n",
733 ICPU.Scanline, reg>>4, (signed char) byte);
735 S9xSetSoundVolume (reg >> 4, (signed char) byte,
736 (signed char) APU.DSP [reg + 1]);
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])
751 if (Settings.TraceSoundDSP)
752 S9xTraceSoundDSP ("[%d] %d volume right: %d\n",
753 ICPU.Scanline, reg >>4, (signed char) byte);
755 S9xSetSoundVolume (reg >> 4, (signed char) APU.DSP [reg - 1],
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:
769 if (Settings.TraceSoundDSP)
770 S9xTraceSoundDSP ("[%d] %d freq low: %d\n",
771 ICPU.Scanline, reg>>4, byte);
773 S9xSetSoundHertz (reg >> 4, (((byte + (APU.DSP [reg + 1] << 8)) & FREQUENCY_MASK) * 32000) >> 12);
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:
785 if (Settings.TraceSoundDSP)
786 S9xTraceSoundDSP ("[%d] %d freq high: %d\n",
787 ICPU.Scanline, reg>>4, byte);
789 S9xSetSoundHertz (reg >> 4,
790 (((byte << 8) + APU.DSP [reg - 1]) & FREQUENCY_MASK) * 8);
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])
804 if (Settings.TraceSoundDSP)
805 S9xTraceSoundDSP ("[%d] %d sample number: %d\n",
806 ICPU.Scanline, reg>>4, byte);
808 //S9xSetSoundSample (reg >> 4, byte); // notaz: seems to be unused?
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])
823 if (Settings.TraceSoundDSP)
824 S9xTraceSoundDSP ("[%d] %d adsr1: %02x\n",
825 ICPU.Scanline, reg>>4, byte);
828 S9xFixEnvelope (reg >> 4, APU.DSP [reg + 2], byte,
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])
845 if (Settings.TraceSoundDSP)
846 S9xTraceSoundDSP ("[%d] %d adsr2: %02x\n",
847 ICPU.Scanline, reg>>4, byte);
850 S9xFixEnvelope (reg >> 4, APU.DSP [reg + 1], APU.DSP [reg - 1],
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])
867 if (Settings.TraceSoundDSP)
868 S9xTraceSoundDSP ("[%d] %d gain: %02x\n",
869 ICPU.Scanline, reg>>4, byte);
872 S9xFixEnvelope (reg >> 4, byte, APU.DSP [reg - 2],
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:
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:
900 if (Settings.TraceSoundDSP)
901 S9xTraceSoundDSP ("[%d] Sample directory to: %02x\n",
902 ICPU.Scanline, byte);
907 if (byte != APU.DSP [APU_PMON])
910 if (Settings.TraceSoundDSP)
912 S9xTraceSoundDSP ("[%d] FreqMod:", ICPU.Scanline);
914 for (int c = 0; c < 8; c++, mask <<= 1)
918 if (APU.DSP [reg] & mask)
919 S9xTraceSoundDSP ("%d", c);
921 S9xTraceSoundDSP ("%d(on),", c);
925 if (APU.DSP [reg] & mask)
926 S9xTraceSoundDSP ("%d(off),", c);
929 S9xTraceSoundDSP ("\n");
932 S9xSetFrequencyModulationEnable (byte);
937 if (byte != APU.DSP [APU_EON])
940 if (Settings.TraceSoundDSP)
942 S9xTraceSoundDSP ("[%d] Echo:", ICPU.Scanline);
944 for (int c = 0; c < 8; c++, mask <<= 1)
948 if (APU.DSP [reg] & mask)
949 S9xTraceSoundDSP ("%d", c);
951 S9xTraceSoundDSP ("%d(on),", c);
955 if (APU.DSP [reg] & mask)
956 S9xTraceSoundDSP ("%d(off),", c);
959 S9xTraceSoundDSP ("\n");
962 S9xSetEchoEnable (byte);
967 S9xSetEchoFeedback ((signed char) byte);
974 S9xSetEchoDelay (byte & 0xf);
985 S9xSetFilterCoefficient (reg >> 4, (signed char) byte);
989 //printf ("Write %02x to unknown APU register %02x\n", byte, reg);
997 APU.DSP [reg] = byte;
1000 void S9xFixEnvelope (int channel, uint8 gain, uint8 adsr1, uint8 adsr2)
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
1009 if (S9xSetSoundMode (channel, MODE_ADSR))
1011 S9xSetSoundADSR (channel, adsr1 & 0xf, (adsr1 >> 4) & 7, adsr2 & 0x1f, (adsr2 >> 5) & 7, 8);
1017 if ((gain & 0x80) == 0)
1019 if (S9xSetSoundMode (channel, MODE_GAIN))
1021 S9xSetEnvelopeRate (channel, 0, 0, gain & 0x7f, 0);
1022 S9xSetEnvelopeHeight (channel, gain & 0x7f);
1031 if (S9xSetSoundMode (channel, (gain & 0x20) ?
1032 MODE_INCREASE_BENT_LINE :
1033 MODE_INCREASE_LINEAR))
1035 S9xSetEnvelopeRate (channel, IncreaseRate [gain & 0x1f], 1, 127, (3<<28)|gain);
1041 if (S9xSetSoundMode (channel, MODE_DECREASE_EXPONENTIAL))
1042 S9xSetEnvelopeRate (channel, DecreaseRateExp [gain & 0x1f] / 2, -1, 0, (4<<28)|gain);
1044 if (S9xSetSoundMode (channel, MODE_DECREASE_LINEAR))
1045 S9xSetEnvelopeRate (channel, IncreaseRate [gain & 0x1f], -1, 0, (3<<28)|gain);
1052 void S9xSetAPUControl (uint8 byte)
1055 //printf ("*** Special SPC700 timing enabled\n");
1056 if ((byte & 1) != 0 && !APU.TimerEnabled [0])
1059 IAPU.RAM [0xfd] = 0;
1060 if ((APU.TimerTarget [0] = IAPU.RAM [0xfa]) == 0)
1061 APU.TimerTarget [0] = 0x100;
1063 if ((byte & 2) != 0 && !APU.TimerEnabled [1])
1066 IAPU.RAM [0xfe] = 0;
1067 if ((APU.TimerTarget [1] = IAPU.RAM [0xfb]) == 0)
1068 APU.TimerTarget [1] = 0x100;
1070 if ((byte & 4) != 0 && !APU.TimerEnabled [2])
1073 IAPU.RAM [0xff] = 0;
1074 if ((APU.TimerTarget [2] = IAPU.RAM [0xfc]) == 0)
1075 APU.TimerTarget [2] = 0x100;
1077 APU.TimerEnabled [0] = byte & 1;
1078 APU.TimerEnabled [1] = (byte & 2) >> 1;
1079 APU.TimerEnabled [2] = (byte & 4) >> 2;
1082 IAPU.RAM [0xF4] = IAPU.RAM [0xF5] = 0;
1085 IAPU.RAM [0xF6] = IAPU.RAM [0xF7] = 0;
1091 memmove (&IAPU.RAM [0xffc0], APUROM, sizeof (APUROM));
1099 APU.ShowROM = FALSE;
1100 memmove (&IAPU.RAM [0xffc0], APU.ExtraRAM, sizeof (APUROM));
1103 IAPU.RAM [0xf1] = byte;
1106 void S9xSetAPUTimer (uint16 Address, uint8 byte)
1108 IAPU.RAM [Address] = byte;
1113 if ((APU.TimerTarget [0] = IAPU.RAM [0xfa]) == 0)
1114 APU.TimerTarget [0] = 0x100;
1115 APU.TimerValueWritten [0] = TRUE;
1118 if ((APU.TimerTarget [1] = IAPU.RAM [0xfb]) == 0)
1119 APU.TimerTarget [1] = 0x100;
1120 APU.TimerValueWritten [1] = TRUE;
1123 if ((APU.TimerTarget [2] = IAPU.RAM [0xfc]) == 0)
1124 APU.TimerTarget [2] = 0x100;
1125 APU.TimerValueWritten [2] = TRUE;
1130 uint8 S9xGetAPUDSP ()
1132 uint8 reg = IAPU.RAM [0xf2] & 0x7f;
1133 uint8 byte = APU.DSP [reg];
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)
1151 return ((SoundData.channels [reg >> 4].sample >> 8) |
1152 (SoundData.channels [reg >> 4].sample & 0xff));
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:
1163 // return ((uint8) S9xGetEnvelopeHeight (reg >> 4));
1166 // To fix speech in Magical Drop 2 6/11/00
1167 // APU.DSP [APU_ENDX] = 0;