AY: this sucks, part 1

This commit is contained in:
tildearrow 2025-03-07 20:19:24 -05:00
parent cb67527103
commit 9681f25e54
4 changed files with 215 additions and 171 deletions

View file

@ -248,40 +248,74 @@ void DivPlatformAY8910::checkWrites() {
} }
} }
void DivPlatformAY8910::acquire_mame(short** buf, size_t len) { void DivPlatformAY8910::acquire_mame(blip_buffer_t** bb, size_t len) {
thread_local short ayBuf[3]; thread_local short ayBuf[3];
for (int i=0; i<3; i++) { for (int i=0; i<3; i++) {
oscBuf[i]->begin(len); oscBuf[i]->begin(len);
} }
if (sunsoft) {
for (size_t i=0; i<len; i++) { for (size_t i=0; i<len; i++) {
runDAC(); int advance=len-i;
runTFX(); // heuristic
for (int j=0; j<3; j++) {
// tone counter
const int period=MAX(1,ay->m_tone[j].period)*(ay->m_step_mul<<1);
const int remain=period-ay->m_tone[j].count;
if (remain<advance) advance=remain;
// envelope
if (j<1) {
if (ay->m_envelope[j].holding==0) {
const int periodEnv=MAX(1,ay->m_envelope[j].period)*ay->m_env_step_mul;
const int remainEnv=periodEnv-ay->m_envelope[j].count;
if (remainEnv<advance) advance=remainEnv;
}
}
}
// noise
const int noisePeriod=((int)ay->noise_period())*ay->m_step_mul;
const int noiseRemain=noisePeriod-ay->m_count_noise;
if (noiseRemain<advance) advance=noiseRemain;
//runDAC();
//runTFX();
if (!writes.empty() || advance<1) advance=1;
checkWrites(); checkWrites();
ay->sound_stream_update(ayBuf,1); ay->sound_stream_update(ayBuf,advance);
buf[0][i]=ayBuf[0]; i+=advance-1;
buf[1][i]=buf[0][i];
if (sunsoft) {
if (lastOut[0]!=ayBuf[0]) {
blip_add_delta(bb[0],i,ayBuf[0]-lastOut[0]);
blip_add_delta(bb[1],i,ayBuf[0]-lastOut[0]);
lastOut[0]=ayBuf[0];
}
oscBuf[0]->putSample(i,CLAMP(sunsoftVolTable[31-(ay->lastIndx&31)]<<3,-32768,32767)); oscBuf[0]->putSample(i,CLAMP(sunsoftVolTable[31-(ay->lastIndx&31)]<<3,-32768,32767));
oscBuf[1]->putSample(i,CLAMP(sunsoftVolTable[31-((ay->lastIndx>>5)&31)]<<3,-32768,32767)); oscBuf[1]->putSample(i,CLAMP(sunsoftVolTable[31-((ay->lastIndx>>5)&31)]<<3,-32768,32767));
oscBuf[2]->putSample(i,CLAMP(sunsoftVolTable[31-((ay->lastIndx>>10)&31)]<<3,-32768,32767)); oscBuf[2]->putSample(i,CLAMP(sunsoftVolTable[31-((ay->lastIndx>>10)&31)]<<3,-32768,32767));
} else {
if (stereo) {
int out0=ayBuf[0]+ayBuf[1]+((ayBuf[2]*stereoSep)>>8);
int out1=((ayBuf[0]*stereoSep)>>8)+ayBuf[1]+ayBuf[2];
if (lastOut[0]!=out0) {
blip_add_delta(bb[0],i,out0-lastOut[0]);
lastOut[0]=out0;
}
if (lastOut[1]!=out1) {
blip_add_delta(bb[1],i,out1-lastOut[1]);
lastOut[1]=out1;
} }
} else { } else {
for (size_t i=0; i<len; i++) { int out=ayBuf[0]+ayBuf[1]+ayBuf[2];
runDAC(); if (lastOut[0]!=out) {
runTFX(); blip_add_delta(bb[0],i,out-lastOut[0]);
checkWrites(); blip_add_delta(bb[1],i,out-lastOut[0]);
lastOut[0]=out;
ay->sound_stream_update(ayBuf,1); }
if (stereo) {
buf[0][i]=ayBuf[0]+ayBuf[1]+((ayBuf[2]*stereoSep)>>8);
buf[1][i]=((ayBuf[0]*stereoSep)>>8)+ayBuf[1]+ayBuf[2];
} else {
buf[0][i]=ayBuf[0]+ayBuf[1]+ayBuf[2];
buf[1][i]=buf[0][i];
} }
oscBuf[0]->putSample(i,ayBuf[0]<<2); oscBuf[0]->putSample(i,ayBuf[0]<<2);
@ -330,11 +364,14 @@ void DivPlatformAY8910::acquire_atomic(short** buf, size_t len) {
} }
} }
void DivPlatformAY8910::acquireDirect(blip_buffer_t** bb, size_t len) {
if (selCore && !intellivision) return;
acquire_mame(bb,len);
}
void DivPlatformAY8910::acquire(short** buf, size_t len) { void DivPlatformAY8910::acquire(short** buf, size_t len) {
if (selCore && !intellivision) { if (selCore && !intellivision) {
acquire_atomic(buf,len); acquire_atomic(buf,len);
} else {
acquire_mame(buf,len);
} }
} }
@ -1011,6 +1048,8 @@ void DivPlatformAY8910::reset() {
ayEnvSlideLow=0; ayEnvSlideLow=0;
delay=0; delay=0;
lastOut[0]=0;
lastOut[1]=0;
ioPortA=false; ioPortA=false;
ioPortB=false; ioPortB=false;
@ -1026,6 +1065,10 @@ bool DivPlatformAY8910::keyOffAffectsArp(int ch) {
return true; return true;
} }
bool DivPlatformAY8910::hasAcquireDirect() {
return (!selCore || intellivision);
}
bool DivPlatformAY8910::getLegacyAlwaysSetVolume() { bool DivPlatformAY8910::getLegacyAlwaysSetVolume() {
return false; return false;
} }

View file

@ -128,6 +128,7 @@ class DivPlatformAY8910: public DivDispatch {
ssg_t ay_atomic; ssg_t ay_atomic;
int delay; int delay;
int lastOut[2];
bool extMode; bool extMode;
unsigned int extClock; unsigned int extClock;
@ -149,7 +150,7 @@ class DivPlatformAY8910: public DivDispatch {
void checkWrites(); void checkWrites();
void updateOutSel(bool immediate=false); void updateOutSel(bool immediate=false);
void acquire_mame(short** buf, size_t len); void acquire_mame(blip_buffer_t** bb, size_t len);
void acquire_atomic(short** buf, size_t len); void acquire_atomic(short** buf, size_t len);
friend void putDispatchChip(void*,int); friend void putDispatchChip(void*,int);
@ -160,6 +161,7 @@ class DivPlatformAY8910: public DivDispatch {
void runTFX(int runRate=0); void runTFX(int runRate=0);
void setExtClockDiv(unsigned int eclk=COLOR_NTSC, unsigned char ediv=8); void setExtClockDiv(unsigned int eclk=COLOR_NTSC, unsigned char ediv=8);
void acquire(short** buf, size_t len); void acquire(short** buf, size_t len);
void acquireDirect(blip_buffer_t** bb, size_t len);
void fillStream(std::vector<DivDelayedWrite>& stream, int sRate, size_t len); void fillStream(std::vector<DivDelayedWrite>& stream, int sRate, size_t len);
int dispatch(DivCommand c); int dispatch(DivCommand c);
void* getChanState(int chan); void* getChanState(int chan);
@ -177,6 +179,7 @@ class DivPlatformAY8910: public DivDispatch {
void setFlags(const DivConfig& flags); void setFlags(const DivConfig& flags);
int getOutputCount(); int getOutputCount();
bool keyOffAffectsArp(int ch); bool keyOffAffectsArp(int ch);
bool hasAcquireDirect();
DivMacroInt* getChanMacroInt(int ch); DivMacroInt* getChanMacroInt(int ch);
DivSamplePos getSamplePos(int ch); DivSamplePos getSamplePos(int ch);
bool getLegacyAlwaysSetVolume(); bool getLegacyAlwaysSetVolume();

View file

@ -1035,13 +1035,11 @@ void ay8910_device::ay8910_write_reg(int r, int v)
// sound_stream_update - handle a stream update // sound_stream_update - handle a stream update
//------------------------------------------------- //-------------------------------------------------
void ay8910_device::sound_stream_update(short* outputs, int outLen) void ay8910_device::sound_stream_update(short* outputs, int advance)
{ {
tone_t *tone; tone_t *tone;
envelope_t *envelope; envelope_t *envelope;
int samples = outLen;
/* hack to prevent us from hanging when starting filtered outputs */ /* hack to prevent us from hanging when starting filtered outputs */
if (!m_ready) if (!m_ready)
{ {
@ -1056,14 +1054,12 @@ void ay8910_device::sound_stream_update(short* outputs, int outLen)
/* Note that this means that if both tone and noise are disabled, the output */ /* Note that this means that if both tone and noise are disabled, the output */
/* is 1, not 0, and can be modulated changing the volume. */ /* is 1, not 0, and can be modulated changing the volume. */
/* buffering loop */ /* loop? kill the loop and optimize! */
for (int sampindex = 0; sampindex < samples; sampindex++)
{
for (int chan = 0; chan < NUM_CHANNELS; chan++) for (int chan = 0; chan < NUM_CHANNELS; chan++)
{ {
tone = &m_tone[chan]; tone = &m_tone[chan];
const int period = std::max<int>(1, tone->period) * (m_step_mul << 1); const int period = std::max<int>(1, tone->period) * (m_step_mul << 1);
tone->count += is_expanded_mode() ? 32 : ((m_feature & PSG_HAS_EXPANDED_MODE) ? 1 : 2); tone->count += advance << (is_expanded_mode() ? 5 : ((m_feature & PSG_HAS_EXPANDED_MODE) ? 0 : 1));
if (tone->count>=period) { if (tone->count>=period) {
tone->duty_cycle = (tone->duty_cycle - (tone->count/period)) & 0x1f; tone->duty_cycle = (tone->duty_cycle - (tone->count/period)) & 0x1f;
tone->output = is_expanded_mode() ? BIT(duty_cycle[tone_duty(tone)], tone->duty_cycle) : BIT(tone->duty_cycle, 0); tone->output = is_expanded_mode() ? BIT(duty_cycle[tone_duty(tone)], tone->duty_cycle) : BIT(tone->duty_cycle, 0);
@ -1072,12 +1068,13 @@ void ay8910_device::sound_stream_update(short* outputs, int outLen)
} }
const int period_noise = (int)(noise_period()) * m_step_mul; const int period_noise = (int)(noise_period()) * m_step_mul;
if ((++m_count_noise) >= period_noise) m_count_noise+=advance;
while (m_count_noise >= period_noise)
{ {
/* toggle the prescaler output. Noise is no different to /* toggle the prescaler output. Noise is no different to
* channels. * channels.
*/ */
m_count_noise = 0; m_count_noise -= period_noise;
m_prescale_noise = (m_prescale_noise + 1) & ((m_feature & PSG_HAS_EXPANDED_MODE) ? 3 : 1); m_prescale_noise = (m_prescale_noise + 1) & ((m_feature & PSG_HAS_EXPANDED_MODE) ? 3 : 1);
if (is_expanded_mode()) // AY8930 noise generator rate is twice? compares as compatibility mode if (is_expanded_mode()) // AY8930 noise generator rate is twice? compares as compatibility mode
@ -1110,15 +1107,17 @@ void ay8910_device::sound_stream_update(short* outputs, int outLen)
} }
/* update envelope */ /* update envelope */
for (int chan = 0; chan < NUM_CHANNELS; chan++) // who cares about env 1/2 on 8910
for (int chan = 0; chan < (is_expanded_mode() ? NUM_CHANNELS : 1); chan++)
{ {
envelope = &m_envelope[chan]; envelope = &m_envelope[chan];
if (envelope->holding == 0) if (envelope->holding == 0)
{ {
const int period = std::max<int>(1, envelope->period) * m_env_step_mul; const int period = std::max<int>(1, envelope->period) * m_env_step_mul;
if ((++envelope->count) >= period) envelope->count += advance;
if (envelope->count >= period)
{ {
envelope->count = 0; envelope->count %= period;
envelope->step--; envelope->step--;
/* check envelope current position */ /* check envelope current position */
@ -1195,7 +1194,6 @@ void ay8910_device::sound_stream_update(short* outputs, int outLen)
{ {
outputs[0]=mix_3D(); outputs[0]=mix_3D();
} }
}
} }
void ay8910_device::build_mixer_table() void ay8910_device::build_mixer_table()

View file

@ -164,7 +164,7 @@ public:
unsigned char ay8910_read_ym(); unsigned char ay8910_read_ym();
void ay8910_reset_ym(); void ay8910_reset_ym();
private: public:
static constexpr int NUM_CHANNELS = 3; static constexpr int NUM_CHANNELS = 3;
device_type chip_type; device_type chip_type;