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 EXTERN_C void S9xMixSamplesO(signed short *buffer, int sample_count, int sample_offset);
166 void S9xSetPlaybackRate (uint32 rate);
167 bool8 S9xInitSound (void);
172 // notaz: some stuff from soundux.cpp to enable their inlining
175 //#include <dprintf.h>
177 extern int Echo [24000];
178 extern int Loop [16];
179 extern int FilterTaps [8];
180 extern int EchoBuffer [SOUND_BUFFER_SIZE];
181 extern int NoiseFreq [32];
183 // precalculated env rates for S9xSetEnvRate
184 extern unsigned long AttackERate [16][10];
185 extern unsigned long DecayERate [8][10];
186 extern unsigned long SustainERate [32][10];
187 extern unsigned long IncreaseERate [32][10];
188 extern unsigned long DecreaseERateExp[32][10];
189 extern unsigned long KeyOffERate[10];
192 #define FIXED_POINT 0x10000UL
200 static inline void S9xSetSoundMute (bool8 mute)
201 { so.mute_sound = mute;}
203 static inline void S9xSetEnvRate (Channel *ch, unsigned long rate, int direction, int target, unsigned int mode)
205 ch->envx_target = target;
213 ch->direction = direction;
216 if (rate == 0 || so.playback_rate == 0)
222 ch->erate = AttackERate[ch->env_ind_attack][ch->state];
226 ch->erate = DecayERate[ch->env_ind_decay][ch->state];
230 ch->erate = SustainERate[ch->env_ind_sustain][ch->state];
234 ch->erate = IncreaseERate[mode&0x1f][ch->state];
237 case 4: // DecreaseExp
238 ch->erate = DecreaseERateExp[mode&0x1f][ch->state];
242 ch->erate = KeyOffERate[ch->state];
248 static int steps [] =
250 // 0, 64, 1238, 1238, 256, 1, 64, 109, 64, 1238
251 0, 64, 619, 619, 128, 1, 64, 55, 64, 619
254 if (rate == 0 || so.playback_rate == 0)
258 ch->erate = (unsigned long)
259 (((int64) FIXED_POINT * 1000 * steps [ch->state]) /
260 (rate * so.playback_rate));
265 static inline void S9xSetEchoEnable (uint8 byte)
267 SoundData.echo_channel_enable = byte;
268 if (!SoundData.echo_write_enabled || Settings.DisableSoundEcho)
270 if (byte && !SoundData.echo_enable)
272 memset (Echo, 0, sizeof (Echo));
273 memset (Loop, 0, sizeof (Loop));
276 SoundData.echo_enable = byte;
277 for (int i = 0; i < 8; i++)
280 SoundData.channels [i].echo_buf_ptr = EchoBuffer;
282 SoundData.channels [i].echo_buf_ptr = 0;
286 static inline void S9xSetEchoFeedback (int feedback)
289 SoundData.echo_feedback = feedback;
292 static inline void S9xSetFilterCoefficient (int tap, int value)
294 FilterTaps [tap & 7] = value;
295 SoundData.no_filter = (FilterTaps [0] == 127 || FilterTaps [0] == 0) &&
296 FilterTaps [1] == 0 &&
297 FilterTaps [2] == 0 &&
298 FilterTaps [3] == 0 &&
299 FilterTaps [4] == 0 &&
300 FilterTaps [5] == 0 &&
301 FilterTaps [6] == 0 &&
305 static inline uint16 *S9xGetSampleAddress (int sample_number)
307 uint32 addr = (((APU.DSP[APU_DIR] << 8) + (sample_number << 2)) & 0xffff);
308 return (uint16 *)(IAPU.RAM + addr);
311 static inline void S9xSetSoundFrequency (int channel, int hertz) // hertz [0~64K<<1]
313 if (so.playback_rate)
315 if (SoundData.channels[channel].type == SOUND_NOISE)
316 hertz = NoiseFreq [APU.DSP [APU_FLG] & 0x1f];
317 #if 0 // notaz: this compiles to something awful
318 SoundData.channels[channel].frequency = (int)
319 (((int64) hertz * FIXED_POINT) / so.playback_rate);
321 SoundData.channels[channel].frequency = (hertz * so.freqbase) >> 11;
324 /* if (Settings.FixFrequency)
326 SoundData.channels[channel].frequency =
327 (unsigned long) ((double) SoundData.channels[channel].frequency * 0.980);