AY: this sucks, part 1
This commit is contained in:
parent
cb67527103
commit
9681f25e54
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue