Skip to content

Commit 9834f47

Browse files
committed
SNES: S9xMixSamples now supports an arbitrary MixBuffer size
Which means no more crash if we increase sampling rate, as well as the ability to reduce memory usage significantly later on.
1 parent da4f587 commit 9834f47

File tree

1 file changed

+73
-58
lines changed

1 file changed

+73
-58
lines changed

retro-core/components/snes9x/src/soundux.c

Lines changed: 73 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@
1919
#define CLIP8(v) \
2020
(v) = (((v) <= -128) ? -128 : (((v) >= 127) ? 127 : (v)))
2121

22+
#define MIX_BUFFER_SIZE SOUND_BUFFER_SIZE
2223
static struct {
23-
int32_t wave[SOUND_BUFFER_SIZE];
24-
int32_t Echo [24000];
25-
int32_t MixBuffer [SOUND_BUFFER_SIZE];
26-
int32_t EchoBuffer [SOUND_BUFFER_SIZE];
24+
int32_t wave[MIX_BUFFER_SIZE / 2];
25+
int32_t Echo [16000]; // (512 * 0xF * so.playback_rate) / 32040 * 2
26+
int32_t MixBuffer [MIX_BUFFER_SIZE];
27+
int32_t EchoBuffer [MIX_BUFFER_SIZE];
2728
int32_t FilterTaps [8];
28-
uint8_t FilterTapDefinitionBitfield;
29+
uint32_t FilterTapDefinitionBitfield;
2930
/* In the above, bit I is set if FilterTaps[I] is non-zero. */
3031
uint32_t Z;
3132
int32_t Loop [16];
@@ -95,6 +96,11 @@ static const uint32_t IncreaseRate [32] =
9596

9697
#define SustainRate DecreaseRateExp
9798

99+
static const int32_t EnvSteps [10] =
100+
{
101+
0, 64, 619, 619, 128, 1, 64, 55, 64, 619
102+
};
103+
98104
#define FIXED_POINT 0x10000UL
99105
#define FIXED_POINT_REMAINDER 0xffffUL
100106
#define FIXED_POINT_SHIFT 16
@@ -231,8 +237,12 @@ void S9xSetEchoFeedback(int32_t feedback)
231237

232238
void S9xSetEchoDelay(int32_t delay)
233239
{
234-
SoundData.echo_buffer_size = (512 * delay * so.playback_rate) / 32040;
240+
SoundData.echo_buffer_size = (512 * (delay & 0xF) * so.playback_rate) / 32040;
235241
SoundData.echo_buffer_size <<= 1;
242+
// This can happen if so.playback_rate frequency is higher than 32040. This check replaces a possible crash with at worse bogus echo...
243+
// You have to enlarge Echo to accommodate higher playback rate
244+
if (SoundData.echo_buffer_size > sizeof(Echo) / sizeof(Echo[0]))
245+
SoundData.echo_buffer_size = sizeof(Echo) / sizeof(Echo[0]);
236246
if (SoundData.echo_buffer_size)
237247
SoundData.echo_ptr %= SoundData.echo_buffer_size;
238248
else
@@ -755,72 +765,78 @@ stereo_exit:;
755765

756766
void S9xMixSamples(int16_t* buffer, int32_t sample_count)
757767
{
758-
int32_t J;
759-
int32_t I;
768+
for (int32_t remaining = sample_count; remaining > 0; remaining -= sample_count)
769+
{
770+
sample_count = MIN(sizeof(MixBuffer) / sizeof(MixBuffer[0]), remaining);
760771

761-
if (SoundData.echo_enable)
762-
memset(EchoBuffer, 0, sample_count * sizeof(EchoBuffer [0]));
763-
memset(MixBuffer, 0, sample_count * sizeof(MixBuffer [0]));
764-
MixStereo(sample_count);
772+
int32_t J;
773+
int32_t I;
765774

766-
/* Mix and convert waveforms */
767-
if (SoundData.echo_enable && SoundData.echo_buffer_size)
768-
{
769-
/* 16-bit stereo sound with echo enabled ... */
770-
if (FilterTapDefinitionBitfield == 0)
775+
if (SoundData.echo_enable && SoundData.echo_buffer_size)
776+
memset(EchoBuffer, 0, sample_count * sizeof(EchoBuffer [0]));
777+
memset(MixBuffer, 0, sample_count * sizeof(MixBuffer [0]));
778+
MixStereo(sample_count);
779+
780+
/* Mix and convert waveforms */
781+
if (SoundData.echo_enable && SoundData.echo_buffer_size)
771782
{
772-
/* ... but no filter defined. */
773-
for (J = 0; J < sample_count; J++)
783+
/* 16-bit stereo sound with echo enabled ... */
784+
if (FilterTapDefinitionBitfield == 0)
774785
{
775-
int32_t E = Echo [SoundData.echo_ptr];
776-
Echo[SoundData.echo_ptr++] = (E * SoundData.echo_feedback) / 128 + EchoBuffer [J];
786+
/* ... but no filter defined. */
787+
for (J = 0; J < sample_count; J++)
788+
{
789+
int32_t E = Echo [SoundData.echo_ptr];
790+
Echo[SoundData.echo_ptr++] = (E * SoundData.echo_feedback) / 128 + EchoBuffer [J];
777791

778-
if (SoundData.echo_ptr >= SoundData.echo_buffer_size)
779-
SoundData.echo_ptr = 0;
792+
if (SoundData.echo_ptr >= SoundData.echo_buffer_size)
793+
SoundData.echo_ptr = 0;
780794

781-
I = (MixBuffer[J] * SoundData.master_volume [J & 1] + E * SoundData.echo_volume [J & 1]) / VOL_DIV16;
782-
CLIP16(I);
783-
buffer[J] = I;
795+
I = (MixBuffer[J] * SoundData.master_volume [J & 1] + E * SoundData.echo_volume [J & 1]) / VOL_DIV16;
796+
CLIP16(I);
797+
buffer[J] = I;
798+
}
799+
}
800+
else
801+
{
802+
/* ... with filter defined. */
803+
for (J = 0; J < sample_count; J++)
804+
{
805+
int32_t E;
806+
Loop [(Z - 0) & 15] = Echo [SoundData.echo_ptr];
807+
E = Loop [(Z - 0) & 15] * FilterTaps [0];
808+
if (FilterTapDefinitionBitfield & 0x02) E += Loop [(Z - 2) & 15] * FilterTaps [1];
809+
if (FilterTapDefinitionBitfield & 0x04) E += Loop [(Z - 4) & 15] * FilterTaps [2];
810+
if (FilterTapDefinitionBitfield & 0x08) E += Loop [(Z - 6) & 15] * FilterTaps [3];
811+
if (FilterTapDefinitionBitfield & 0x10) E += Loop [(Z - 8) & 15] * FilterTaps [4];
812+
if (FilterTapDefinitionBitfield & 0x20) E += Loop [(Z - 10) & 15] * FilterTaps [5];
813+
if (FilterTapDefinitionBitfield & 0x40) E += Loop [(Z - 12) & 15] * FilterTaps [6];
814+
if (FilterTapDefinitionBitfield & 0x80) E += Loop [(Z - 14) & 15] * FilterTaps [7];
815+
E /= 128;
816+
Z++;
817+
818+
Echo[SoundData.echo_ptr++] = (E * SoundData.echo_feedback) / 128 + EchoBuffer[J];
819+
820+
if (SoundData.echo_ptr >= SoundData.echo_buffer_size)
821+
SoundData.echo_ptr = 0;
822+
823+
I = (MixBuffer[J] * SoundData.master_volume [J & 1] + E * SoundData.echo_volume [J & 1]) / VOL_DIV16;
824+
CLIP16(I);
825+
buffer[J] = I;
826+
}
784827
}
785828
}
786829
else
787830
{
788-
/* ... with filter defined. */
831+
/* 16-bit mono or stereo sound, no echo */
789832
for (J = 0; J < sample_count; J++)
790833
{
791-
int32_t E;
792-
Loop [(Z - 0) & 15] = Echo [SoundData.echo_ptr];
793-
E = Loop [(Z - 0) & 15] * FilterTaps [0];
794-
if (FilterTapDefinitionBitfield & 0x02) E += Loop [(Z - 2) & 15] * FilterTaps [1];
795-
if (FilterTapDefinitionBitfield & 0x04) E += Loop [(Z - 4) & 15] * FilterTaps [2];
796-
if (FilterTapDefinitionBitfield & 0x08) E += Loop [(Z - 6) & 15] * FilterTaps [3];
797-
if (FilterTapDefinitionBitfield & 0x10) E += Loop [(Z - 8) & 15] * FilterTaps [4];
798-
if (FilterTapDefinitionBitfield & 0x20) E += Loop [(Z - 10) & 15] * FilterTaps [5];
799-
if (FilterTapDefinitionBitfield & 0x40) E += Loop [(Z - 12) & 15] * FilterTaps [6];
800-
if (FilterTapDefinitionBitfield & 0x80) E += Loop [(Z - 14) & 15] * FilterTaps [7];
801-
E /= 128;
802-
Z++;
803-
804-
Echo[SoundData.echo_ptr++] = (E * SoundData.echo_feedback) / 128 + EchoBuffer[J];
805-
806-
if (SoundData.echo_ptr >= SoundData.echo_buffer_size)
807-
SoundData.echo_ptr = 0;
808-
809-
I = (MixBuffer[J] * SoundData.master_volume [J & 1] + E * SoundData.echo_volume [J & 1]) / VOL_DIV16;
834+
I = (MixBuffer[J] * SoundData.master_volume [J & 1]) / VOL_DIV16;
810835
CLIP16(I);
811836
buffer[J] = I;
812837
}
813838
}
814-
}
815-
else
816-
{
817-
/* 16-bit mono or stereo sound, no echo */
818-
for (J = 0; J < sample_count; J++)
819-
{
820-
I = (MixBuffer[J] * SoundData.master_volume [J & 1]) / VOL_DIV16;
821-
CLIP16(I);
822-
buffer[J] = I;
823-
}
839+
buffer += sample_count;
824840
}
825841
}
826842

@@ -912,7 +928,6 @@ void S9xSetPlaybackRate(uint32_t playback_rate)
912928

913929
if (playback_rate)
914930
{
915-
int32_t steps [] = {0, 64, 619, 619, 128, 1, 64, 55, 64, 619};
916931
int32_t i, u;
917932

918933
/* notaz: calculate a value (let's call it freqbase) to simplify channel freq calculations later. */
@@ -921,7 +936,7 @@ void S9xSetPlaybackRate(uint32_t playback_rate)
921936

922937
for (u = 0 ; u < 10 ; u++)
923938
{
924-
int64_t fp1000su = ((int64_t) FIXED_POINT * 1000 * steps[u]);
939+
int64_t fp1000su = ((int64_t) FIXED_POINT * 1000 * EnvSteps[u]);
925940

926941
for (i = 0 ; i < 16 ; i++)
927942
AttackERate[i][u] = (uint32_t) (fp1000su / (AttackRate[i] * playback_rate));

0 commit comments

Comments
 (0)