diff options
Diffstat (limited to 'source/soundux.c')
-rw-r--r-- | source/soundux.c | 645 |
1 files changed, 231 insertions, 414 deletions
diff --git a/source/soundux.c b/source/soundux.c index 280c9f9..9e71bae 100644 --- a/source/soundux.c +++ b/source/soundux.c @@ -6,21 +6,19 @@ #include <stdio.h> #include <string.h> #include <errno.h> -#include <fcntl.h> #define CLIP16(v) \ - if ((v) < -32768) \ +if ((v) < -32768) \ (v) = -32768; \ - else \ - if ((v) > 32767) \ -(v) = 32767 +else \ +if ((v) > 32767) \ + (v) = 32767 #define CLIP8(v) \ - if ((v) < -128) \ +if ((v) < -128) \ (v) = -128; \ - else \ - if ((v) > 127) \ -(v) = 127 +else if ((v) > 127) \ + (v) = 127 #include "snes9x.h" #include "soundux.h" @@ -29,7 +27,6 @@ #include "cpuexec.h" extern int32_t Echo [24000]; -extern int32_t DummyEchoBuffer [SOUND_BUFFER_SIZE]; extern int32_t MixBuffer [SOUND_BUFFER_SIZE]; extern int32_t EchoBuffer [SOUND_BUFFER_SIZE]; extern int32_t FilterTaps [8]; @@ -40,6 +37,42 @@ extern int32_t Loop [16]; extern long FilterValues[4][2]; extern int32_t NoiseFreq [32]; +uint32_t AttackRate [16] = +{ + 4100, 2600, 1500, 1000, 640, 380, 260, 160, + 96, 64, 40, 24, 16, 10, 6, 1 +}; + +uint32_t DecayRate [8] = +{ + 1200, 740, 440, 290, 180, 110, 74, 37 +}; + +uint32_t DecreaseRateExp [32] = +{ + 0xFFFFFFFF, 38000, 28000, 24000, 19000, 14000, 12000, 9400, + 7100, 5900, 4700, 3500, 2900, 2400, 1800, 1500, + 1200, 880, 740, 590, 440, 370, 290, 220, + 180, 150, 110, 92, 74, 55, 37, 18 +}; + +uint32_t IncreaseRate [32] = +{ + 0xFFFFFFFF, 4100, 3100, 2600, 2000, 1500, 1300, 1000, + 770, 640, 510, 380, 320, 260, 190, 160, + 130, 96, 80, 64, 48, 40, 32, 24, + 20, 16, 12, 10, 8, 6, 4, 2 +}; + +#define SustainRate DecreaseRateExp + +// precalculated env rates for S9xSetEnvRate +uint32_t AttackERate [16][10]; +uint32_t DecayERate [8][10]; +uint32_t SustainERate [32][10]; +uint32_t IncreaseERate [32][10]; +uint32_t DecreaseERateExp[32][10]; +uint32_t KeyOffERate [10]; static int32_t noise_gen; @@ -51,7 +84,6 @@ static int32_t noise_gen; #define ENVX_SHIFT 24 void DecodeBlockAsm(int8_t*, int16_t*, int32_t*, int32_t*); -void DecodeBlockAsm2(int8_t*, int16_t*, int32_t*, int32_t*); // 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. @@ -60,17 +92,6 @@ void DecodeBlockAsm2(int8_t*, int16_t*, int32_t*, int32_t*); #define LAST_SAMPLE 0xffffff #define JUST_PLAYED_LAST_SAMPLE(c) ((c)->sample_pointer >= LAST_SAMPLE) -void S9xSetEightBitConsoleSound(bool Enabled) -{ - if (Settings.EightBitConsoleSound != Enabled) - { - Settings.EightBitConsoleSound = Enabled; - int i; - for (i = 0; i < 8; i++) - SoundData.channels[i].needs_decode = true; - } -} - static inline uint8_t* S9xGetSampleAddress(int sample_number) { uint32_t addr = (((APU.DSP[APU_DIR] << 8) + (sample_number << 2)) & 0xffff); @@ -92,7 +113,7 @@ void S9xAPUSetEndX(int ch) APU.DSP [APU_ENDX] |= 1 << ch; } -void S9xSetEnvRate(Channel* ch, uint32_t rate, int direction, int target) +void S9xSetEnvRate(Channel* ch, uint32_t rate, int direction, int target, unsigned int mode) { ch->envx_target = target; @@ -104,38 +125,39 @@ void S9xSetEnvRate(Channel* ch, uint32_t rate, int direction, int target) else ch->direction = direction; - static int64_t steps [] = - { - // 0, 64, 1238, 1238, 256, 1, 64, 109, 64, 1238 - 0, - (int64_t) FIXED_POINT * 1000 * 64, - (int64_t) FIXED_POINT * 1000 * 619, - (int64_t) FIXED_POINT * 1000 * 619, - (int64_t) FIXED_POINT * 1000 * 128, - (int64_t) FIXED_POINT * 1000 * 1, - (int64_t) FIXED_POINT * 1000 * 64, - (int64_t) FIXED_POINT * 1000 * 55, - (int64_t) FIXED_POINT * 1000 * 64, - (int64_t) FIXED_POINT * 1000 * 619 - }; - if (rate == 0 || so.playback_rate == 0) ch->erate = 0; else { - ch->erate = (uint32_t) - (steps [ch->state] / (rate * so.playback_rate)); + switch (mode >> 28) + { + case 0: // Attack + ch->erate = AttackERate[ch->env_ind_attack][ch->state]; + break; + case 1: // Decay + ch->erate = DecayERate[ch->env_ind_decay][ch->state]; + break; + case 2: // Sustain + ch->erate = SustainERate[ch->env_ind_sustain][ch->state]; + break; + case 3: // Increase + ch->erate = IncreaseERate[mode & 0x1f][ch->state]; + break; + case 4: // DecreaseExp + ch->erate = DecreaseERateExp[mode & 0x1f][ch->state]; + break; + case 5: // KeyOff + ch->erate = KeyOffERate[ch->state]; + break; + } } } - -void S9xSetEnvelopeRate(int channel, uint32_t rate, int direction, - int target) +void S9xSetEnvelopeRate(int channel, uint32_t rate, int direction, int target, unsigned int mode) { - S9xSetEnvRate(&SoundData.channels [channel], rate, direction, target); + S9xSetEnvRate(&SoundData.channels [channel], rate, direction, target, mode); } - void S9xSetSoundVolume(int channel, int16_t volume_left, int16_t volume_right) { Channel* ch = &SoundData.channels[channel]; @@ -180,7 +202,7 @@ void S9xSetEchoEnable(uint8_t byte) if (byte & (1 << i)) SoundData.channels [i].echo_buf_ptr = EchoBuffer; else - SoundData.channels [i].echo_buf_ptr = DummyEchoBuffer; + SoundData.channels [i].echo_buf_ptr = NULL; } } @@ -192,7 +214,7 @@ void S9xSetEchoFeedback(int feedback) void S9xSetEchoDelay(int delay) { - SoundData.echo_buffer_size = (512 * delay * so.playback_rate) / 32000; + SoundData.echo_buffer_size = (512 * delay * so.playback_rate) >> 15; SoundData.echo_buffer_size <<= 1; if (SoundData.echo_buffer_size) SoundData.echo_ptr %= SoundData.echo_buffer_size; @@ -209,7 +231,7 @@ void S9xSetEchoWriteEnable(uint8_t byte) void S9xSetFrequencyModulationEnable(uint8_t byte) { - SoundData.pitch_mod = byte & ~1; + SoundData.pitch_mod = byte & 0xFE; } void S9xSetSoundKeyOff(int channel) @@ -220,7 +242,7 @@ void S9xSetSoundKeyOff(int channel) { ch->state = SOUND_RELEASE; ch->mode = MODE_RELEASE; - S9xSetEnvRate(ch, 8, -1, 0); + S9xSetEnvRate(ch, 8, -1, 0, 5 << 28); } } @@ -247,10 +269,8 @@ void S9xFixSoundAfterSnapshotLoad() 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_t) - SoundData.channels [i].previous16 [0]; - SoundData.channels [i].previous [1] = (int32_t) - SoundData.channels [i].previous16 [1]; + SoundData.channels [i].previous [0] = (int32_t) SoundData.channels [i].previous16 [0]; + SoundData.channels [i].previous [1] = (int32_t) SoundData.channels [i].previous16 [1]; } IAPU.Scanline = 0; } @@ -264,10 +284,21 @@ void S9xSetFilterCoefficient(int tap, int value) FilterTapDefinitionBitfield |= 1 << (tap & 7); } -void S9xSetSoundADSR(int channel, int attack_rate, int decay_rate, - int sustain_rate, int sustain_level, int release_rate) +void S9xSetSoundADSR(int channel, int attack_ind, int decay_ind, int sustain_ind, int sustain_level, int release_rate) { + int attack_rate = AttackRate [attack_ind]; + int decay_rate = DecayRate [decay_ind]; + int sustain_rate = SustainRate [sustain_ind]; + + // Hack for ROMs that use a very short attack rate, key on a + // channel, then switch to decay mode. e.g. Final Fantasy II. + if(attack_rate == 1) + attack_rate = 0; + Channel* ch = &SoundData.channels[channel]; + ch->env_ind_attack = attack_ind; + ch->env_ind_decay = decay_ind; + ch->env_ind_sustain = sustain_ind; ch->attack_rate = attack_rate; ch->decay_rate = decay_rate; ch->sustain_rate = sustain_rate; @@ -277,15 +308,14 @@ void S9xSetSoundADSR(int channel, int attack_rate, int decay_rate, switch (SoundData.channels[channel].state) { case SOUND_ATTACK: - S9xSetEnvRate(ch, attack_rate, 1, 127); + S9xSetEnvRate(ch, attack_rate, 1, 127, 0); break; - case SOUND_DECAY: S9xSetEnvRate(ch, decay_rate, -1, - (MAX_ENVELOPE_HEIGHT * (sustain_level + 1)) >> 3); + (MAX_ENVELOPE_HEIGHT * (sustain_level + 1)) >> 3, 1 << 28); break; case SOUND_SUSTAIN: - S9xSetEnvRate(ch, sustain_rate, -1, 0); + S9xSetEnvRate(ch, sustain_rate, -1, 0, 2 << 28); break; } } @@ -320,14 +350,13 @@ int S9xGetEnvelopeHeight(int channel) return (0); } -void S9xSetSoundFrequency(int channel, int hertz) +void S9xSetSoundFrequency(int channel, int hertz) // hertz [0~64K<<1] { if (so.playback_rate) { if (SoundData.channels[channel].type == SOUND_NOISE) hertz = NoiseFreq [APU.DSP [APU_FLG] & 0x1f]; - SoundData.channels[channel].frequency = (int) - (((int64_t) hertz * FIXED_POINT) / so.playback_rate); + SoundData.channels[channel].frequency = (hertz * so.freqbase) >> 11; } } @@ -345,13 +374,11 @@ void S9xSetSoundType(int channel, int type_of_sound) void DecodeBlock(Channel* ch) { int32_t out; - unsigned char filter; + uint8_t filter; unsigned char shift; signed char sample1, sample2; - unsigned char i; - bool invalid_header; - if (ch->block_pointer > 0x10000 - 9) + if (ch->block_pointer >= 0x10000 - 9) { ch->last_block = true; ch->loop = false; @@ -359,274 +386,88 @@ void DecodeBlock(Channel* ch) return; } - if (Settings.EightBitConsoleSound) - { - signed char* compressed = (signed char*) &IAPU.RAM [ch->block_pointer]; - - filter = *compressed; - if ((ch->last_block = filter & 1)) - ch->loop = (filter & 2) != 0; - - int16_t interim[16]; - uint8_t interim_byte = 0; - - compressed++; + int8_t* compressed = (int8_t*) &IAPU.RAM [ch->block_pointer]; - // Seperate out the header parts used for decoding + filter = *compressed; + if ((ch->last_block = filter & 1)) + ch->loop = (filter & 2) != 0; - shift = filter >> 4; + int16_t* raw = ch->block = ch->decoded; + unsigned int i; - // Header validity check: if range(shift) is over 12, ignore - // all bits of the data for that block except for the sign bit of each - invalid_header = (shift >= 0xD); + compressed++; - filter = filter & 0x0c; - - int32_t prev0 = ch->previous [0]; - int32_t prev1 = ch->previous [1]; - - int16_t amplitude = 0; + int32_t prev0 = ch->previous [0]; + int32_t prev1 = ch->previous [1]; + shift = filter >> 4; + switch ((filter >> 2) & 3) + { + case 0: for (i = 8; i != 0; i--) { sample1 = *compressed++; sample2 = sample1 << 4; - //Sample 2 = Bottom Nibble, Sign Extended. sample2 >>= 4; - //Sample 1 = Top Nibble, shifted down and Sign Extended. sample1 >>= 4; - if (invalid_header) - { - sample1 >>= 3; - sample2 >>= 3; - } - - int nybblesmp; - for (nybblesmp = 0; nybblesmp < 2; nybblesmp++) - { - out = (((nybblesmp) ? sample2 : sample1) << shift); - out >>= 1; - - switch (filter) - { - case 0x00: - // Method0 - [Smp] - break; - - case 0x04: - // Method1 - [Delta]+[Smp-1](15/16) - out += (prev0 >> 1) + ((-prev0) >> 5); - break; - - case 0x08: - // Method2 - [Delta]+[Smp-1](61/32)-[Smp-2](15/16) - out += (prev0) + ((-(prev0 + (prev0 >> 1))) >> 5) - (prev1 >> 1) + (prev1 >> 5); - break; - - default: - // Method3 - [Delta]+[Smp-1](115/64)-[Smp-2](13/16) - out += (prev0) + ((-(prev0 + (prev0 << 2) + (prev0 << 3))) >> 7) - - (prev1 >> 1) + ((prev1 + (prev1 >> 1)) >> 4); - break; - - } - CLIP16(out); - int16_t result = (int16_t)(out << 1); - if (abs(result) > amplitude) - amplitude = abs(result); - interim[interim_byte++] = out; - prev1 = (int16_t)prev0; - prev0 = (int16_t)(out << 1); - } - } - ch->previous [0] = prev0; - ch->previous [1] = prev1; - - int32_t total_deviation_from_previous = 0; - for (i = 1; i < 16; i++) - total_deviation_from_previous += abs(interim[i] - interim[i - 1]); - if (total_deviation_from_previous >= (int32_t) amplitude * 4) - { - /* Looks like noise. Generate noise. */ - for (i = 0; i < 16; i++) - { - int feedback = (noise_gen << 13) ^ (noise_gen << 14); - noise_gen = (feedback & 0x4000) ^ (noise_gen >> 1); - ch->decoded[i] = (noise_gen << 17) >> 17; - } - } - else if (interim[0] < interim[1] && interim[1] < interim[2] - && interim[2] < interim[3] - && interim[4] > interim[5] && interim[5] > interim[6] - && interim[6] > interim[7] && interim[7] > interim[8] - && interim[8] > interim[9] && interim[9] > interim[10] - && interim[10] > interim[11] - && interim[12] < interim[13] && interim[13] < interim[14] - && interim[14] < interim[15]) - { - /* Looks like a sine or triangle wave. Make it a - * triangle wave with an amplitude equivalent to that - * of the highest amplitude sample of the block. */ - ch->decoded[0] = ch->decoded[8] = 0; - ch->decoded[1] = ch->decoded[7] = amplitude / 4; - ch->decoded[2] = ch->decoded[6] = amplitude / 2; - ch->decoded[3] = ch->decoded[5] = amplitude * 3 / 4; - ch->decoded[4] = amplitude; - ch->decoded[9] = ch->decoded[15] = -(amplitude / 4); - ch->decoded[10] = ch->decoded[14] = -(amplitude / 2); - ch->decoded[11] = ch->decoded[13] = -(amplitude * 3 / 4); - ch->decoded[12] = -amplitude; - } - else if (interim[0] > interim[1] && interim[1] > interim[2] - && interim[2] > interim[3] - && interim[4] < interim[5] && interim[5] < interim[6] - && interim[6] < interim[7] && interim[7] < interim[8] - && interim[8] < interim[9] && interim[9] < interim[10] - && interim[10] < interim[11] - && interim[12] > interim[13] && interim[13] > interim[14] - && interim[14] > interim[15]) - { - /* Inverted triangle wave. */ - ch->decoded[0] = ch->decoded[8] = 0; - ch->decoded[1] = ch->decoded[7] = -(amplitude / 4); - ch->decoded[2] = ch->decoded[6] = -(amplitude / 2); - ch->decoded[3] = ch->decoded[5] = -(amplitude * 3 / 4); - ch->decoded[4] = -amplitude; - ch->decoded[9] = ch->decoded[15] = amplitude / 4; - ch->decoded[10] = ch->decoded[14] = amplitude / 2; - ch->decoded[11] = ch->decoded[13] = amplitude * 3 / 4; - ch->decoded[12] = amplitude; - } - else if (interim[0] < interim[1] && interim[1] < interim[2] - && interim[2] < interim[3] && interim[3] < interim[4] - && interim[4] < interim[5] && interim[5] < interim[6] - && interim[6] < interim[7] - && interim[8] > interim[9] && interim[9] > interim[10] - && interim[10] > interim[11] && interim[11] > interim[12] - && interim[12] > interim[13] && interim[13] > interim[14] - && interim[14] > interim[15]) - { - /* Looks like a V wave. Make it a half-triangle wave - * with an amplitude equivalent to that - * of the highest amplitude sample of the block. */ - ch->decoded[0] = 0; - ch->decoded[1] = ch->decoded[15] = amplitude / 8; - ch->decoded[2] = ch->decoded[14] = amplitude / 4; - ch->decoded[3] = ch->decoded[13] = amplitude * 3 / 8; - ch->decoded[4] = ch->decoded[12] = amplitude / 2; - ch->decoded[5] = ch->decoded[11] = amplitude * 5 / 8; - ch->decoded[6] = ch->decoded[10] = amplitude * 3 / 4; - ch->decoded[7] = ch->decoded[9] = amplitude * 7 / 8; - ch->decoded[8] = amplitude; + *raw++ = ((int32_t) sample1 << shift); + *raw++ = ((int32_t) sample2 << shift); } - else if (interim[0] > interim[1] && interim[1] > interim[2] - && interim[2] > interim[3] && interim[3] > interim[4] - && interim[4] > interim[5] && interim[5] > interim[6] - && interim[6] > interim[7] - && interim[8] < interim[9] && interim[9] < interim[10] - && interim[10] < interim[11] && interim[11] < interim[12] - && interim[12] < interim[13] && interim[13] < interim[14] - && interim[14] < interim[15]) + prev1 = *(raw - 2); + prev0 = *(raw - 1); + break; + case 1: + for (i = 8; i != 0; i--) { - /* Inverted V wave. */ - ch->decoded[0] = 0; - ch->decoded[1] = ch->decoded[15] = -(amplitude / 8); - ch->decoded[2] = ch->decoded[14] = -(amplitude / 4); - ch->decoded[3] = ch->decoded[13] = -(amplitude * 3 / 8); - ch->decoded[4] = ch->decoded[12] = -(amplitude / 2); - ch->decoded[5] = ch->decoded[11] = -(amplitude * 5 / 8); - ch->decoded[6] = ch->decoded[10] = -(amplitude * 3 / 4); - ch->decoded[7] = ch->decoded[9] = -(amplitude * 7 / 8); - ch->decoded[8] = -amplitude; + sample1 = *compressed++; + sample2 = sample1 << 4; + sample2 >>= 4; + sample1 >>= 4; + prev0 = (int16_t) prev0; + *raw++ = prev1 = ((int32_t) sample1 << shift) + prev0 - (prev0 >> 4); + prev1 = (int16_t) prev1; + *raw++ = prev0 = ((int32_t) sample2 << shift) + prev1 - (prev1 >> 4); } - else + break; + case 2: + for (i = 8; i != 0; i--) { - // Make it a square wave with an amplitude equivalent to that - // of the highest amplitude sample of the block. - // But actually put half of the amplitude, because - // square waves are just loud. - for (i = 0; i < 8; i++) - ch->decoded[i] = amplitude / 2; - for (i = 8; i < 16; i++) - ch->decoded[i] = -(amplitude / 2); + sample1 = *compressed++; + sample2 = sample1 << 4; + sample2 >>= 4; + sample1 >>= 4; + out = (sample1 << shift) - prev1 + (prev1 >> 4); + prev1 = (int16_t) prev0; + prev0 &= ~3; + *raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 5) - (prev0 >> 4); + out = (sample2 << shift) - prev1 + (prev1 >> 4); + prev1 = (int16_t) prev0; + prev0 &= ~3; + *raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 5) - (prev0 >> 4); } - } - else - { - signed char* compressed = (signed char*) &IAPU.RAM [ch->block_pointer]; - - filter = *compressed; - if ((ch->last_block = filter & 1)) - ch->loop = (filter & 2) != 0; - - compressed++; - int16_t* raw = ch->block = ch->decoded; - - // Seperate out the header parts used for decoding - - shift = filter >> 4; - - // Header validity check: if range(shift) is over 12, ignore - // all bits of the data for that block except for the sign bit of each - invalid_header = (shift >= 0xD); - - filter = filter & 0x0c; - - int32_t prev0 = ch->previous [0]; - int32_t prev1 = ch->previous [1]; - + break; + case 3: for (i = 8; i != 0; i--) { sample1 = *compressed++; sample2 = sample1 << 4; - //Sample 2 = Bottom Nibble, Sign Extended. sample2 >>= 4; - //Sample 1 = Top Nibble, shifted down and Sign Extended. sample1 >>= 4; - if (invalid_header) - { - sample1 >>= 3; - sample2 >>= 3; - } - - int nybblesmp; - for (nybblesmp = 0; nybblesmp < 2; nybblesmp++) - { - out = (((nybblesmp) ? sample2 : sample1) << shift); - out >>= 1; - - switch (filter) - { - case 0x00: - // Method0 - [Smp] - break; - - case 0x04: - // Method1 - [Delta]+[Smp-1](15/16) - out += (prev0 >> 1) + ((-prev0) >> 5); - break; - - case 0x08: - // Method2 - [Delta]+[Smp-1](61/32)-[Smp-2](15/16) - out += (prev0) + ((-(prev0 + (prev0 >> 1))) >> 5) - (prev1 >> 1) + (prev1 >> 5); - break; - - default: - // Method3 - [Delta]+[Smp-1](115/64)-[Smp-2](13/16) - out += (prev0) + ((-(prev0 + (prev0 << 2) + (prev0 << 3))) >> 7) - - (prev1 >> 1) + ((prev1 + (prev1 >> 1)) >> 4); - break; - - } - CLIP16(out); - *raw++ = (int16_t)(out << 1); - prev1 = (int16_t)prev0; - prev0 = (int16_t)(out << 1); - } + out = (sample1 << shift); + out = out - prev1 + (prev1 >> 3) + (prev1 >> 4); + prev1 = (int16_t) prev0; + prev0 &= ~3; + *raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 3) - (prev0 >> 4) - (prev1 >> 6); + out = (sample2 << shift); + out = out - prev1 + (prev1 >> 3) + (prev1 >> 4); + prev1 = (int16_t) prev0; + prev0 &= ~3; + *raw++ = prev0 = out + (prev0 << 1) - (prev0 >> 3) - (prev0 >> 4) - (prev1 >> 6); } - ch->previous [0] = prev0; - ch->previous [1] = prev1; + break; } + ch->previous [0] = prev0; + ch->previous [1] = prev1; ch->block_pointer += 9; } @@ -641,7 +482,7 @@ static inline void MixStereo(int sample_count) { Channel* ch = &SoundData.channels[J]; - if (ch->state == SOUND_SILENT || !(so.sound_switch & (1 << J))) + if (ch->state == SOUND_SILENT) continue; int32_t VL, VR; @@ -698,15 +539,13 @@ static inline void MixStereo(int sample_count) if (ch->sustain_level != 8) { S9xSetEnvRate(ch, ch->decay_rate, -1, - (MAX_ENVELOPE_HEIGHT * ch->sustain_level) - >> 3); + (MAX_ENVELOPE_HEIGHT * ch->sustain_level) >> 3, 1 << 28); break; } ch->state = SOUND_SUSTAIN; - S9xSetEnvRate(ch, ch->sustain_rate, -1, 0); + S9xSetEnvRate(ch, ch->sustain_rate, -1, 0, 2 << 28); } break; - case SOUND_DECAY: while (ch->env_error >= FIXED_POINT) { @@ -722,10 +561,9 @@ static inline void MixStereo(int sample_count) goto stereo_exit; } ch->state = SOUND_SUSTAIN; - S9xSetEnvRate(ch, ch->sustain_rate, -1, 0); + S9xSetEnvRate(ch, ch->sustain_rate, -1, 0, 2 << 28); } break; - case SOUND_SUSTAIN: while (ch->env_error >= FIXED_POINT) { @@ -739,7 +577,6 @@ static inline void MixStereo(int sample_count) goto stereo_exit; } break; - case SOUND_RELEASE: while (ch->env_error >= FIXED_POINT) { @@ -753,7 +590,6 @@ static inline void MixStereo(int sample_count) goto stereo_exit; } break; - case SOUND_INCREASE_LINEAR: ch->env_error &= FIXED_POINT_REMAINDER; ch->envx += step << 1; @@ -765,10 +601,9 @@ static inline void MixStereo(int sample_count) ch->envxx = 127 << ENVX_SHIFT; ch->state = SOUND_GAIN; ch->mode = MODE_GAIN; - S9xSetEnvRate(ch, 0, -1, 0); + S9xSetEnvRate(ch, 0, -1, 0, 0); } break; - case SOUND_INCREASE_BENT_LINE: if (ch->envx >= (MAX_ENVELOPE_HEIGHT * 3) / 4) { @@ -792,10 +627,9 @@ static inline void MixStereo(int sample_count) ch->envxx = 127 << ENVX_SHIFT; ch->state = SOUND_GAIN; ch->mode = MODE_GAIN; - S9xSetEnvRate(ch, 0, -1, 0); + S9xSetEnvRate(ch, 0, -1, 0, 0); } break; - case SOUND_DECREASE_LINEAR: ch->env_error &= FIXED_POINT_REMAINDER; ch->envx -= step << 1; @@ -806,7 +640,6 @@ static inline void MixStereo(int sample_count) goto stereo_exit; } break; - case SOUND_DECREASE_EXPONENTIAL: while (ch->env_error >= FIXED_POINT) { @@ -820,9 +653,8 @@ static inline void MixStereo(int sample_count) goto stereo_exit; } break; - case SOUND_GAIN: - S9xSetEnvRate(ch, 0, -1, 0); + S9xSetEnvRate(ch, 0, -1, 0, 0); break; } ch-> left_vol_level = (ch->envx * ch->volume_left) / 128; @@ -916,6 +748,10 @@ static inline void MixStereo(int sample_count) MixBuffer [I ] += VL; MixBuffer [I + 1] += VR; + + if (!ch->echo_buf_ptr) + continue; + ch->echo_buf_ptr [I ] += VL; ch->echo_buf_ptr [I + 1] += VR; } @@ -924,11 +760,17 @@ stereo_exit: } } -void S9xMixSamples(uint8_t* buffer, int sample_count) +void S9xMixSamples(uint16_t* buffer, int sample_count) { int J; int I; + if (so.mute_sound) + { + memset(buffer, 0, sample_count * sizeof(buffer [0])); + return; + } + if (SoundData.echo_enable) memset(EchoBuffer, 0, sample_count * sizeof(EchoBuffer [0])); memset(MixBuffer, 0, sample_count * sizeof(MixBuffer [0])); @@ -944,19 +786,14 @@ void S9xMixSamples(uint8_t* buffer, int sample_count) for (J = 0; J < sample_count; J++) { int E = Echo [SoundData.echo_ptr]; + Echo[SoundData.echo_ptr++] = (E * SoundData.echo_feedback) / 128 + EchoBuffer [J]; - Echo [SoundData.echo_ptr] = (E * SoundData.echo_feedback) / 128 + - EchoBuffer [J]; - - if ((SoundData.echo_ptr += 1) >= SoundData.echo_buffer_size) + if (SoundData.echo_ptr >= SoundData.echo_buffer_size) SoundData.echo_ptr = 0; - I = (MixBuffer [J] * - SoundData.master_volume [J & 1] + - E * SoundData.echo_volume [J & 1]) / VOL_DIV16; - + I = (MixBuffer[J] * SoundData.master_volume [J & 1] + E * SoundData.echo_volume [J & 1]) / VOL_DIV16; CLIP16(I); - ((int16_t*) buffer)[J] = I; + buffer[J] = I; } } else @@ -964,39 +801,26 @@ void S9xMixSamples(uint8_t* buffer, int sample_count) // ... with filter defined. for (J = 0; J < sample_count; J++) { - int E = Echo [SoundData.echo_ptr]; - - Loop [(Z - 0) & 15] = E; - E = E * FilterTaps [0]; - if (FilterTapDefinitionBitfield & 0x02) E += Loop [(Z - 2) & 15] * - FilterTaps [1]; - if (FilterTapDefinitionBitfield & 0x04) E += Loop [(Z - 4) & 15] * - FilterTaps [2]; - if (FilterTapDefinitionBitfield & 0x08) E += Loop [(Z - 6) & 15] * - FilterTaps [3]; - if (FilterTapDefinitionBitfield & 0x10) E += Loop [(Z - 8) & 15] * - FilterTaps [4]; - if (FilterTapDefinitionBitfield & 0x20) E += Loop [(Z - 10) & 15] * - FilterTaps [5]; - if (FilterTapDefinitionBitfield & 0x40) E += Loop [(Z - 12) & 15] * - FilterTaps [6]; - if (FilterTapDefinitionBitfield & 0x80) E += Loop [(Z - 14) & 15] * - FilterTaps [7]; + Loop [(Z - 0) & 15] = Echo [SoundData.echo_ptr]; + int E = Loop [(Z - 0) & 15] * FilterTaps [0]; + if (FilterTapDefinitionBitfield & 0x02) E += Loop [(Z - 2) & 15] * FilterTaps [1]; + if (FilterTapDefinitionBitfield & 0x04) E += Loop [(Z - 4) & 15] * FilterTaps [2]; + if (FilterTapDefinitionBitfield & 0x08) E += Loop [(Z - 6) & 15] * FilterTaps [3]; + if (FilterTapDefinitionBitfield & 0x10) E += Loop [(Z - 8) & 15] * FilterTaps [4]; + if (FilterTapDefinitionBitfield & 0x20) E += Loop [(Z - 10) & 15] * FilterTaps [5]; + if (FilterTapDefinitionBitfield & 0x40) E += Loop [(Z - 12) & 15] * FilterTaps [6]; + if (FilterTapDefinitionBitfield & 0x80) E += Loop [(Z - 14) & 15] * FilterTaps [7]; E /= 128; Z++; - Echo [SoundData.echo_ptr] = (E * SoundData.echo_feedback) / 128 + - EchoBuffer [J]; + Echo[SoundData.echo_ptr++] = (E * SoundData.echo_feedback) / 128 + EchoBuffer[J]; - if ((SoundData.echo_ptr += 1) >= SoundData.echo_buffer_size) + if (SoundData.echo_ptr >= SoundData.echo_buffer_size) SoundData.echo_ptr = 0; - I = (MixBuffer [J] * - SoundData.master_volume [J & 1] + - E * SoundData.echo_volume [J & 1]) / VOL_DIV16; - + I = (MixBuffer[J] * SoundData.master_volume [J & 1] + E * SoundData.echo_volume [J & 1]) / VOL_DIV16; CLIP16(I); - ((int16_t*) buffer)[J] = I; + buffer[J] = I; } } } @@ -1005,14 +829,11 @@ void S9xMixSamples(uint8_t* buffer, int sample_count) // 16-bit mono or stereo sound, no echo for (J = 0; J < sample_count; J++) { - I = (MixBuffer [J] * - SoundData.master_volume [J & 1]) / VOL_DIV16; - + I = (MixBuffer[J] * SoundData.master_volume [J & 1]) / VOL_DIV16; CLIP16(I); - ((int16_t*) buffer)[J] = I; + buffer[J] = I; } } - } void S9xResetSound(bool full) @@ -1041,6 +862,10 @@ void S9xResetSound(bool full) SoundData.channels[i].sustain_rate = 0; SoundData.channels[i].release_rate = 0; SoundData.channels[i].sustain_level = 0; + // notaz + SoundData.channels[i].env_ind_attack = 0; + SoundData.channels[i].env_ind_decay = 0; + SoundData.channels[i].env_ind_sustain = 0; SoundData.echo_ptr = 0; SoundData.echo_feedback = 0; SoundData.echo_buffer_size = 1; @@ -1055,10 +880,6 @@ void S9xResetSound(bool full) FilterTaps [7] = 0; FilterTapDefinitionBitfield = 0; noise_gen = 1; - so.sound_switch = 255; - so.samples_mixed_so_far = 0; - so.play_position = 0; - so.err_counter = 0; if (full) { @@ -1066,9 +887,6 @@ void S9xResetSound(bool full) SoundData.echo_write_enabled = 0; SoundData.echo_channel_enable = 0; SoundData.pitch_mod = 0; - SoundData.dummy[0] = 0; - SoundData.dummy[1] = 0; - SoundData.dummy[2] = 0; SoundData.master_volume[0] = 0; SoundData.master_volume[1] = 0; SoundData.echo_volume[0] = 0; @@ -1077,18 +895,46 @@ void S9xResetSound(bool full) } SoundData.master_volume [0] = SoundData.master_volume [1] = 127; - if (so.playback_rate) - so.err_rate = (uint32_t)(FIXED_POINT * SNES_SCANLINE_TIME / - (1.0 / so.playback_rate)); - else - so.err_rate = 0; + so.mute_sound = true; } void S9xSetPlaybackRate(uint32_t playback_rate) { so.playback_rate = playback_rate; - so.err_rate = (uint32_t)(SNES_SCANLINE_TIME * FIXED_POINT / (1.0 / - (double) so.playback_rate)); + + if (playback_rate) + { + // notaz: calculate a value (let's call it freqbase) to simplify channel freq calculations later. + so.freqbase = (FIXED_POINT << 11) / (playback_rate * 33 / 32); + // now precalculate env rates for S9xSetEnvRate + static int steps [] = + { + 0, 64, 619, 619, 128, 1, 64, 55, 64, 619 + }; + + int i, u; + + for (u = 0 ; u < 10 ; u++) + { + int64_t fp1000su = ((int64_t) FIXED_POINT * 1000 * steps[u]); + + for (i = 0 ; i < 16 ; i++) + AttackERate[i][u] = (uint32_t) (fp1000su / (AttackRate[i] * playback_rate)); + + for (i = 0 ; i < 8 ; i++) + DecayERate[i][u] = (uint32_t) (fp1000su / (DecayRate[i] * playback_rate)); + + for (i = 0 ; i < 32 ; i++) + { + SustainERate[i][u] = (uint32_t) (fp1000su / (SustainRate[i] * playback_rate)); + IncreaseERate[i][u] = (uint32_t) (fp1000su / (IncreaseRate[i] * playback_rate)); + DecreaseERateExp[i][u] = (uint32_t) (fp1000su / (DecreaseRateExp[i] / 2 * playback_rate)); + } + + KeyOffERate[u] = (uint32_t) (fp1000su / (8 * playback_rate)); + } + } + S9xSetEchoDelay(APU.DSP [APU_EDL] & 0xf); int i; for (i = 0; i < 8; i++) @@ -1097,13 +943,8 @@ void S9xSetPlaybackRate(uint32_t playback_rate) bool S9xInitSound() { - so.sound_fd = -1; - so.sound_switch = 255; - so.playback_rate = 0; - so.buffer_size = 0; - so.encoded = false; - + S9xResetSound(true); return (1); } @@ -1120,20 +961,9 @@ bool S9xSetSoundMode(int channel, int mode) return (true); } break; - case MODE_DECREASE_LINEAR: case MODE_DECREASE_EXPONENTIAL: case MODE_GAIN: - if (ch->mode != MODE_RELEASE) - { - ch->mode = mode; - if (ch->state != SOUND_SILENT) - ch->state = mode; - - return (true); - } - break; - case MODE_INCREASE_LINEAR: case MODE_INCREASE_BENT_LINE: if (ch->mode != MODE_RELEASE) @@ -1141,11 +971,9 @@ bool S9xSetSoundMode(int channel, int mode) ch->mode = mode; if (ch->state != SOUND_SILENT) ch->state = mode; - return (true); } break; - case MODE_ADSR: if (ch->mode == MODE_NONE || ch->mode == MODE_ADSR) { @@ -1157,11 +985,6 @@ bool S9xSetSoundMode(int channel, int mode) return (false); } -void S9xSetSoundControl(int sound_switch) -{ - so.sound_switch = sound_switch; -} - void S9xPlaySample(int channel) { Channel* ch = &SoundData.channels[channel]; @@ -1202,14 +1025,14 @@ void S9xPlaySample(int channel) { ch->state = SOUND_SUSTAIN; ch->envx = (MAX_ENVELOPE_HEIGHT * ch->sustain_level) >> 3; - S9xSetEnvRate(ch, ch->sustain_rate, -1, 0); + S9xSetEnvRate(ch, ch->sustain_rate, -1, 0, 2 << 28); } else { ch->state = SOUND_DECAY; ch->envx = MAX_ENVELOPE_HEIGHT; S9xSetEnvRate(ch, ch->decay_rate, -1, - (MAX_ENVELOPE_HEIGHT * ch->sustain_level) >> 3); + (MAX_ENVELOPE_HEIGHT * ch->sustain_level) >> 3, 1 << 28); } ch-> left_vol_level = (ch->envx * ch->volume_left) / 128; ch->right_vol_level = (ch->envx * ch->volume_right) / 128; @@ -1220,31 +1043,25 @@ void S9xPlaySample(int channel) ch->envx = 0; ch->left_vol_level = 0; ch->right_vol_level = 0; - S9xSetEnvRate(ch, ch->attack_rate, 1, MAX_ENVELOPE_HEIGHT); + S9xSetEnvRate(ch, ch->attack_rate, 1, MAX_ENVELOPE_HEIGHT, 0); } ch->envxx = ch->envx << ENVX_SHIFT; break; - case MODE_GAIN: ch->state = SOUND_GAIN; break; - case MODE_INCREASE_LINEAR: ch->state = SOUND_INCREASE_LINEAR; break; - case MODE_INCREASE_BENT_LINE: ch->state = SOUND_INCREASE_BENT_LINE; break; - case MODE_DECREASE_LINEAR: ch->state = SOUND_DECREASE_LINEAR; break; - case MODE_DECREASE_EXPONENTIAL: ch->state = SOUND_DECREASE_EXPONENTIAL; break; - default: break; } |