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.
44 enum { SOUND_SAMPLE = 0, SOUND_NOISE, SOUND_EXTRA_NOISE, SOUND_MUTE };
45 enum { SOUND_SILENT, SOUND_ATTACK, SOUND_DECAY, SOUND_SUSTAIN,
46 SOUND_RELEASE, SOUND_GAIN, SOUND_INCREASE_LINEAR,
47 SOUND_INCREASE_BENT_LINE, SOUND_DECREASE_LINEAR,
48 SOUND_DECREASE_EXPONENTIAL};
50 enum { MODE_NONE = SOUND_SILENT, MODE_ADSR, MODE_RELEASE = SOUND_RELEASE,
51 MODE_GAIN, MODE_INCREASE_LINEAR, MODE_INCREASE_BENT_LINE,
52 MODE_DECREASE_LINEAR, MODE_DECREASE_EXPONENTIAL};
54 #define MAX_ENVELOPE_HEIGHT 127
55 #define ENVELOPE_SHIFT 7
56 #define MAX_VOLUME 127
57 #define VOLUME_SHIFT 7
59 #define SOUND_DECODE_LENGTH 16
61 #define NUM_CHANNELS 8
62 #define SOUND_BUFFER_SIZE (2*44100/50)
63 #define MAX_BUFFER_SIZE SOUND_BUFFER_SIZE
73 uint32 freqbase; // notaz
76 EXTERN_C SoundStatus so;
89 short right_vol_level;
91 unsigned long int env_error;
94 unsigned long attack_rate;
95 unsigned long decay_rate;
96 unsigned long sustain_rate;
97 unsigned long release_rate;
98 unsigned long sustain_level;
100 signed short decoded [16];
101 signed short previous16 [2];
103 uint16 sample_number;
106 uint32 block_pointer;
107 uint32 sample_pointer;
111 signed short next_sample;
115 uint8 env_ind_attack;
117 uint8 env_ind_sustain;
119 // Just incase they are needed in the future, for snapshot compatibility.
121 //I'll use Fatl's recovery on savestates.
124 unsigned short last_valid_header;
129 short master_volume_left;
130 short master_volume_right;
131 short echo_volume_left;
132 short echo_volume_right;
136 int echo_buffer_size;
137 int echo_write_enabled;
138 int echo_channel_enable;
140 // Just incase they are needed in the future, for snapshot compatibility.
142 Channel channels [NUM_CHANNELS];
144 int master_volume [2];
149 EXTERN_C SSoundData SoundData;
151 void S9xSetEnvelopeHeight (int channel, int height);
152 void S9xSetSoundKeyOff (int channel);
153 void S9xSetSoundDecayMode (int channel);
154 void S9xSetSoundAttachMode (int channel);
155 void S9xSoundStartEnvelope (Channel *);
156 void S9xSetSoundSample (int channel, uint16 sample_number);
157 void S9xSetEchoDelay (int byte);
158 void S9xResetSound (bool8 full);
159 void S9xFixSoundAfterSnapshotLoad ();
160 void S9xPlaybackSoundSetting (int channel);
161 void S9xFixEnvelope (int channel, uint8 gain, uint8 adsr1, uint8 adsr2);
162 void S9xStartSample (int channel);
164 EXTERN_C void S9xMixSamples (signed short *buffer, int sample_count);
165 void S9xSetPlaybackRate (uint32 rate);
166 bool8 S9xInitSound (void);
171 // notaz: some stuff from soundux.cpp to enable their inlining
174 //#include <dprintf.h>
176 extern int Echo [24000];
177 extern int Loop [16];
178 extern int FilterTaps [8];
179 extern int EchoBuffer [SOUND_BUFFER_SIZE];
180 extern int NoiseFreq [32];
182 // precalculated env rates for S9xSetEnvRate
183 extern unsigned long AttackERate [16][10];
184 extern unsigned long DecayERate [8][10];
185 extern unsigned long SustainERate [32][10];
186 extern unsigned long IncreaseERate [32][10];
187 extern unsigned long DecreaseERateExp[32][10];
188 extern unsigned long KeyOffERate[10];
191 #define FIXED_POINT 0x10000UL
199 static inline void S9xSetSoundMute (bool8 mute)
200 { so.mute_sound = mute;}
202 static inline void S9xSetEnvRate (Channel *ch, unsigned long rate, int direction, int target, unsigned int mode)
204 ch->envx_target = target;
212 ch->direction = direction;
215 if (rate == 0 || so.playback_rate == 0)
221 ch->erate = AttackERate[ch->env_ind_attack][ch->state];
225 ch->erate = DecayERate[ch->env_ind_decay][ch->state];
229 ch->erate = SustainERate[ch->env_ind_sustain][ch->state];
233 ch->erate = IncreaseERate[mode&0x1f][ch->state];
236 case 4: // DecreaseExp
237 ch->erate = DecreaseERateExp[mode&0x1f][ch->state];
241 ch->erate = KeyOffERate[ch->state];
247 static int steps [] =
249 // 0, 64, 1238, 1238, 256, 1, 64, 109, 64, 1238
250 0, 64, 619, 619, 128, 1, 64, 55, 64, 619
253 if (rate == 0 || so.playback_rate == 0)
257 ch->erate = (unsigned long)
258 (((int64) FIXED_POINT * 1000 * steps [ch->state]) /
259 (rate * so.playback_rate));
264 static inline void S9xSetEchoEnable (uint8 byte)
266 SoundData.echo_channel_enable = byte;
267 if (!SoundData.echo_write_enabled || Settings.DisableSoundEcho)
269 if (byte && !SoundData.echo_enable)
271 memset (Echo, 0, sizeof (Echo));
272 memset (Loop, 0, sizeof (Loop));
275 SoundData.echo_enable = byte;
276 for (int i = 0; i < 8; i++)
279 SoundData.channels [i].echo_buf_ptr = EchoBuffer;
281 SoundData.channels [i].echo_buf_ptr = 0;
285 static inline void S9xSetEchoFeedback (int feedback)
288 SoundData.echo_feedback = feedback;
291 static inline void S9xSetFilterCoefficient (int tap, int value)
293 FilterTaps [tap & 7] = value;
294 SoundData.no_filter = (FilterTaps [0] == 127 || FilterTaps [0] == 0) &&
295 FilterTaps [1] == 0 &&
296 FilterTaps [2] == 0 &&
297 FilterTaps [3] == 0 &&
298 FilterTaps [4] == 0 &&
299 FilterTaps [5] == 0 &&
300 FilterTaps [6] == 0 &&
304 static inline uint16 *S9xGetSampleAddress (int sample_number)
306 uint32 addr = (((APU.DSP[APU_DIR] << 8) + (sample_number << 2)) & 0xffff);
307 return (uint16 *)(IAPU.RAM + addr);
310 static inline void S9xSetSoundFrequency (int channel, int hertz) // hertz [0~64K<<1]
312 if (so.playback_rate)
314 if (SoundData.channels[channel].type == SOUND_NOISE)
315 hertz = NoiseFreq [APU.DSP [APU_FLG] & 0x1f];
316 #if 0 // notaz: this compiles to something awful
317 SoundData.channels[channel].frequency = (int)
318 (((int64) hertz * FIXED_POINT) / so.playback_rate);
320 SoundData.channels[channel].frequency = (hertz * so.freqbase) >> 11;
323 /* if (Settings.FixFrequency)
325 SoundData.channels[channel].frequency =
326 (unsigned long) ((double) SoundData.channels[channel].frequency * 0.980);