📄 soundux.cpp
字号:
/* * Snes9x - Portable Super Nintendo Entertainment System (TM) emulator. * * (c) Copyright 1996 - 2001 Gary Henderson (gary@daniver.demon.co.uk) and * Jerremy Koot (jkoot@snes9x.com) * * Super FX C emulator code * (c) Copyright 1997 - 1999 Ivar (Ivar@snes9x.com) and * Gary Henderson. * Super FX assembler emulator code (c) Copyright 1998 zsKnight and _Demo_. * * DSP1 emulator code (c) Copyright 1998 Ivar, _Demo_ and Gary Henderson. * C4 asm and some C emulation code (c) Copyright 2000 zsKnight and _Demo_. * C4 C code (c) Copyright 2001 Gary Henderson (gary@daniver.demon.co.uk). * * DOS port code contains the works of other authors. See headers in * individual files. * * Snes9x homepage: www.snes9x.com * * Permission to use, copy, modify and distribute Snes9x in both binary and * source form, for non-commercial purposes, is hereby granted without fee, * providing that this license information and copyright notice appear with * all copies and any derived work. * * This software is provided 'as-is', without any express or implied * warranty. In no event shall the authors be held liable for any damages * arising from the use of this software. * * Snes9x is freeware for PERSONAL USE only. Commercial users should * seek permission of the copyright holders first. Commercial use includes * charging money for Snes9x or software derived from Snes9x. * * The copyright holders request that bug fixes and improvements to the code * should be forwarded to them so everyone can benefit from the modifications * in future versions. * * Super NES and Super Nintendo Entertainment System are trademarks of * Nintendo Co., Limited and its subsidiary companies. */#ifdef __DJGPP__#include <allegro.h>#undef TRUE#endif#include <stdlib.h>#include <stdio.h>#include <string.h>#include <errno.h>#include <fcntl.h>#define CLIP16(v) \if ((v) < -32768) \ (v) = -32768; \else \if ((v) > 32767) \ (v) = 32767#define CLIP16_latch(v,l) \if ((v) < -32768) \{ (v) = -32768; (l)++; }\else \if ((v) > 32767) \{ (v) = 32767; (l)++; }#define CLIP24(v) \if ((v) < -8388608) \ (v) = -8388608; \else \if ((v) > 8388607) \ (v) = 8388607#define CLIP8(v) \if ((v) < -128) \ (v) = -128; \else \if ((v) > 127) \ (v) = 127#include "snes9x.h"#include "soundux.h"#include "apu.h"#include "memmap.h"#include "cpuexec.h"extern int Echo [24000];extern int DummyEchoBuffer [SOUND_BUFFER_SIZE];extern int MixBuffer [SOUND_BUFFER_SIZE];extern int EchoBuffer [SOUND_BUFFER_SIZE];extern int FilterTaps [8];extern unsigned long Z;extern int Loop [16];extern long FilterValues[4][2];extern int NoiseFreq [32];#undef ABS#define ABS(a) ((a) < 0 ? -(a) : (a))#define FIXED_POINT 0x10000UL#define FIXED_POINT_REMAINDER 0xffffUL#define FIXED_POINT_SHIFT 16#define VOL_DIV8 0x8000#define VOL_DIV16 0x0080#define ENVX_SHIFT 24extern "C" void DecodeBlockAsm (int8 *, int16 *, int32 *, int32 *);// F is channel's current frequency and M is the 16-bit modulation waveform// from the previous channel multiplied by the current envelope volume level.#define PITCH_MOD(F,M) ((F) * ((((unsigned long) (M)) + 0x800000) >> 16) >> 7)//#define PITCH_MOD(F,M) ((F) * ((((M) & 0x7fffff) >> 14) + 1) >> 8)#define LAST_SAMPLE 0xffffff#define JUST_PLAYED_LAST_SAMPLE(c) ((c)->sample_pointer >= LAST_SAMPLE)STATIC inline uint8 *S9xGetSampleAddress (int sample_number){ uint32 addr = (((APU.DSP[APU_DIR] << 8) + (sample_number << 2)) & 0xffff); return (IAPU.RAM + addr);}void S9xAPUSetEndOfSample (int i, Channel *ch){ ch->state = SOUND_SILENT; ch->mode = MODE_NONE; APU.DSP [APU_ENDX] |= 1 << i; APU.DSP [APU_KON] &= ~(1 << i); APU.DSP [APU_KOFF] &= ~(1 << i); APU.KeyedChannels &= ~(1 << i);}#ifdef __DJGPPEND_OF_FUNCTION (S9xAPUSetEndOfSample)#endifvoid S9xAPUSetEndX (int ch){ APU.DSP [APU_ENDX] |= 1 << ch;}#ifdef __DJGPPEND_OF_FUNCTION (S9xAPUSetEndX)#endifvoid S9xSetEnvRate (Channel *ch, unsigned long rate, int direction, int target){ ch->envx_target = target; if (rate == ~0UL) { ch->direction = 0; rate = 0; } else ch->direction = direction; static int steps [] = {// 0, 64, 1238, 1238, 256, 1, 64, 109, 64, 1238 0, 64, 619, 619, 128, 1, 64, 55, 64, 619 }; if (rate == 0 || so.playback_rate == 0) ch->erate = 0; else { ch->erate = (unsigned long) (((int64) FIXED_POINT * 1000 * steps [ch->state]) / (rate * so.playback_rate)); }}#ifdef __DJGPPEND_OF_FUNCTION(S9xSetEnvRate);#endifvoid S9xSetEnvelopeRate (int channel, unsigned long rate, int direction, int target){ S9xSetEnvRate (&SoundData.channels [channel], rate, direction, target);}#ifdef __DJGPPEND_OF_FUNCTION(S9xSetEnvelopeRate);#endifvoid S9xSetSoundVolume (int channel, short volume_left, short volume_right){ Channel *ch = &SoundData.channels[channel]; if (!so.stereo) volume_left = (ABS(volume_right) + ABS(volume_left)) / 2; ch->volume_left = volume_left; ch->volume_right = volume_right; ch-> left_vol_level = (ch->envx * volume_left) / 128; ch->right_vol_level = (ch->envx * volume_right) / 128;}void S9xSetMasterVolume (short volume_left, short volume_right){ if (Settings.DisableMasterVolume) { SoundData.master_volume_left = 127; SoundData.master_volume_right = 127; SoundData.master_volume [0] = SoundData.master_volume [1] = 127; } else { if (!so.stereo) volume_left = (ABS (volume_right) + ABS (volume_left)) / 2; SoundData.master_volume_left = volume_left; SoundData.master_volume_right = volume_right; SoundData.master_volume [Settings.ReverseStereo] = volume_left; SoundData.master_volume [1 ^ Settings.ReverseStereo] = volume_right; }}void S9xSetEchoVolume (short volume_left, short volume_right){ if (!so.stereo) volume_left = (ABS (volume_right) + ABS (volume_left)) / 2; SoundData.echo_volume_left = volume_left; SoundData.echo_volume_right = volume_right; SoundData.echo_volume [Settings.ReverseStereo] = volume_left; SoundData.echo_volume [1 ^ Settings.ReverseStereo] = volume_right;}void S9xSetEchoEnable (uint8 byte){ SoundData.echo_channel_enable = byte; if (!SoundData.echo_write_enabled || Settings.DisableSoundEcho) byte = 0; if (byte && !SoundData.echo_enable) { memset (Echo, 0, sizeof (Echo)); memset (Loop, 0, sizeof (Loop)); } SoundData.echo_enable = byte; for (int i = 0; i < 8; i++) { if (byte & (1 << i)) SoundData.channels [i].echo_buf_ptr = EchoBuffer; else SoundData.channels [i].echo_buf_ptr = DummyEchoBuffer; }}void S9xSetEchoFeedback (int feedback){ CLIP8(feedback); SoundData.echo_feedback = feedback;}void S9xSetEchoDelay (int delay){ SoundData.echo_buffer_size = (512 * delay * so.playback_rate) / 32000; if (so.stereo) SoundData.echo_buffer_size <<= 1; if (SoundData.echo_buffer_size) SoundData.echo_ptr %= SoundData.echo_buffer_size; else SoundData.echo_ptr = 0; S9xSetEchoEnable (APU.DSP [APU_EON]);}void S9xSetEchoWriteEnable (uint8 byte){ SoundData.echo_write_enabled = byte; S9xSetEchoDelay (APU.DSP [APU_EDL] & 15);}void S9xSetFrequencyModulationEnable (uint8 byte){ SoundData.pitch_mod = byte & ~1;}void S9xSetSoundKeyOff (int channel){ Channel *ch = &SoundData.channels[channel]; if (ch->state != SOUND_SILENT) { ch->state = SOUND_RELEASE; ch->mode = MODE_RELEASE; S9xSetEnvRate (ch, 8, -1, 0); }}void S9xFixSoundAfterSnapshotLoad (){ SoundData.echo_write_enabled = !(APU.DSP [APU_FLG] & 0x20); SoundData.echo_channel_enable = APU.DSP [APU_EON]; S9xSetEchoDelay (APU.DSP [APU_EDL] & 0xf); S9xSetEchoFeedback ((signed char) APU.DSP [APU_EFB]); S9xSetFilterCoefficient (0, (signed char) APU.DSP [APU_C0]); S9xSetFilterCoefficient (1, (signed char) APU.DSP [APU_C1]); S9xSetFilterCoefficient (2, (signed char) APU.DSP [APU_C2]); S9xSetFilterCoefficient (3, (signed char) APU.DSP [APU_C3]); S9xSetFilterCoefficient (4, (signed char) APU.DSP [APU_C4]); S9xSetFilterCoefficient (5, (signed char) APU.DSP [APU_C5]); S9xSetFilterCoefficient (6, (signed char) APU.DSP [APU_C6]); S9xSetFilterCoefficient (7, (signed char) APU.DSP [APU_C7]); for (int i = 0; i < 8; i++) { SoundData.channels[i].needs_decode = TRUE; S9xSetSoundFrequency (i, SoundData.channels[i].hertz); SoundData.channels [i].envxx = SoundData.channels [i].envx << ENVX_SHIFT; SoundData.channels [i].next_sample = 0; SoundData.channels [i].interpolate = 0; SoundData.channels [i].previous [0] = (int32) SoundData.channels [i].previous16 [0]; SoundData.channels [i].previous [1] = (int32) SoundData.channels [i].previous16 [1]; } SoundData.master_volume [Settings.ReverseStereo] = SoundData.master_volume_left; SoundData.master_volume [1 ^ Settings.ReverseStereo] = SoundData.master_volume_right; SoundData.echo_volume [Settings.ReverseStereo] = SoundData.echo_volume_left; SoundData.echo_volume [1 ^ Settings.ReverseStereo] = SoundData.echo_volume_right; IAPU.Scanline = 0;}void S9xSetFilterCoefficient (int tap, int value){ FilterTaps [tap & 7] = value; SoundData.no_filter = (FilterTaps [0] == 127 || FilterTaps [0] == 0) && FilterTaps [1] == 0 && FilterTaps [2] == 0 && FilterTaps [3] == 0 && FilterTaps [4] == 0 && FilterTaps [5] == 0 && FilterTaps [6] == 0 && FilterTaps [7] == 0;}void S9xSetSoundADSR (int channel, int attack_rate, int decay_rate, int sustain_rate, int sustain_level, int release_rate){ SoundData.channels[channel].attack_rate = attack_rate; SoundData.channels[channel].decay_rate = decay_rate; SoundData.channels[channel].sustain_rate = sustain_rate; SoundData.channels[channel].release_rate = release_rate; SoundData.channels[channel].sustain_level = sustain_level + 1; switch (SoundData.channels[channel].state) { case SOUND_ATTACK: S9xSetEnvelopeRate (channel, attack_rate, 1, 127); break; case SOUND_DECAY: S9xSetEnvelopeRate (channel, decay_rate, -1, (MAX_ENVELOPE_HEIGHT * (sustain_level + 1)) >> 3); break; case SOUND_SUSTAIN: S9xSetEnvelopeRate (channel, sustain_rate, -1, 0); break; }}void S9xSetEnvelopeHeight (int channel, int level){ Channel *ch = &SoundData.channels[channel]; ch->envx = level; ch->envxx = level << ENVX_SHIFT; ch->left_vol_level = (level * ch->volume_left) / 128; ch->right_vol_level = (level * ch->volume_right) / 128; if (ch->envx == 0 && ch->state != SOUND_SILENT && ch->state != SOUND_GAIN) { S9xAPUSetEndOfSample (channel, ch); }}int S9xGetEnvelopeHeight (int channel){ if (Settings.SoundEnvelopeHeightReading && SoundData.channels[channel].state != SOUND_SILENT && SoundData.channels[channel].state != SOUND_GAIN) { return (SoundData.channels[channel].envx); } return (0);}#if 1void S9xSetSoundSample (int, uint16) {}#elsevoid S9xSetSoundSample (int channel, uint16 sample_number){ register Channel *ch = &SoundData.channels[channel]; if (ch->state != SOUND_SILENT && sample_number != ch->sample_number) { int keep = ch->state; ch->state = SOUND_SILENT; ch->sample_number = sample_number; ch->loop = FALSE; ch->needs_decode = TRUE; ch->last_block = FALSE; ch->previous [0] = ch->previous[1] = 0; uint8 *dir = S9xGetSampleAddress (sample_number); ch->block_pointer = READ_WORD (dir); ch->sample_pointer = 0; ch->state = keep; }}#endifvoid S9xSetSoundFrequency (int channel, int hertz){ if (so.playback_rate) { if (SoundData.channels[channel].type == SOUND_NOISE) hertz = NoiseFreq [APU.DSP [APU_FLG] & 0x1f]; SoundData.channels[channel].frequency = (int) (((int64) hertz * FIXED_POINT) / so.playback_rate); }}void S9xSetSoundHertz (int channel, int hertz){ SoundData.channels[channel].hertz = hertz; S9xSetSoundFrequency (channel, hertz);}void S9xSetSoundType (int channel, int type_of_sound){ SoundData.channels[channel].type = type_of_sound;}bool8 S9xSetSoundMute (bool8 mute){ bool8 old = so.mute_sound; so.mute_sound = mute; return (old);}void AltDecodeBlock (Channel *ch){ if (ch->block_pointer >= 0x10000 - 9) { ch->last_block = TRUE; ch->loop = FALSE; ch->block = ch->decoded; memset ((void *) ch->decoded, 0, sizeof (int16) * 16); return; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -