From fd9b1dd0f5b336b105c7b6c6762ce332a782d25e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 4 Jan 2023 18:30:29 -0500 Subject: [PATCH] OPL: quad output now that we have this new dispatch output method --- extern/opl/opl3.c | 105 +++++++++++++++++++++++++++--------- extern/opl/opl3.h | 11 ++-- src/engine/platform/opl.cpp | 35 +++++++++--- 3 files changed, 118 insertions(+), 33 deletions(-) diff --git a/extern/opl/opl3.c b/extern/opl/opl3.c index b0a090c5..3358f033 100644 --- a/extern/opl/opl3.c +++ b/extern/opl/opl3.c @@ -946,10 +946,8 @@ static void OPL3_ChannelSetupAlg(opl3_channel *channel) } } -static void OPL3_ChannelWriteC0(opl3_channel *channel, uint8_t data) +static void OPL3_ChannelUpdateAlg(opl3_channel *channel) { - channel->fb = (data & 0x0e) >> 1; - channel->con = data & 0x01; channel->alg = channel->con; if (channel->chip->newm) { @@ -974,14 +972,25 @@ static void OPL3_ChannelWriteC0(opl3_channel *channel, uint8_t data) { OPL3_ChannelSetupAlg(channel); } +} + +static void OPL3_ChannelWriteC0(opl3_channel *channel, uint8_t data) +{ + channel->fb = (data & 0x0e) >> 1; + channel->con = data & 0x01; + OPL3_ChannelUpdateAlg(channel); if (channel->chip->newm) { channel->cha = ((data >> 4) & 0x01) ? ~0 : 0; channel->chb = ((data >> 5) & 0x01) ? ~0 : 0; + channel->chc = ((data >> 6) & 0x01) ? ~0 : 0; + channel->chd = ((data >> 7) & 0x01) ? ~0 : 0; } else { channel->cha = channel->chb = (uint16_t)~0; + // TODO: Verify on real chip if DAC2 output is disabled in compat mode + channel->chc = channel->chd = 0; } #if OPL_ENABLE_STEREOEXT if (!channel->chip->stereoext) @@ -1066,11 +1075,14 @@ static void OPL3_ChannelSet4Op(opl3_chip *chip, uint8_t data) { chip->channel[chnum].chtype = ch_4op; chip->channel[chnum + 3].chtype = ch_4op2; + OPL3_ChannelUpdateAlg(&chip->channel[chnum]); } else { chip->channel[chnum].chtype = ch_2op; chip->channel[chnum + 3].chtype = ch_2op; + OPL3_ChannelUpdateAlg(&chip->channel[chnum]); + OPL3_ChannelUpdateAlg(&chip->channel[chnum+3]); } } } @@ -1096,17 +1108,18 @@ static void OPL3_ProcessSlot(opl3_slot *slot) OPL3_SlotGenerate(slot); } -void OPL3_Generate(opl3_chip *chip, int16_t *buf) +inline void OPL3_Generate4Ch(opl3_chip *chip, int16_t *buf4) { opl3_channel *channel; opl3_writebuf *writebuf; int16_t **out; - int32_t mix; + int32_t mix[2]; uint8_t ii; int16_t accm; uint8_t shift = 0; - buf[1] = OPL3_ClipSample(chip->mixbuff[1]); + buf4[1] = OPL3_ClipSample(chip->mixbuff[1]); + buf4[3] = OPL3_ClipSample(chip->mixbuff[3]); #if OPL_QUIRK_CHANNELSAMPLEDELAY for (ii = 0; ii < 15; ii++) @@ -1117,7 +1130,7 @@ void OPL3_Generate(opl3_chip *chip, int16_t *buf) OPL3_ProcessSlot(&chip->slot[ii]); } - mix = 0; + mix[0] = mix[1] = 0; for (ii = 0; ii < 18; ii++) { channel = &chip->channel[ii]; @@ -1125,12 +1138,14 @@ void OPL3_Generate(opl3_chip *chip, int16_t *buf) out = channel->out; accm = *out[0] + *out[1] + *out[2] + *out[3]; #if OPL_ENABLE_STEREOEXT - mix += (int16_t)((accm * channel->leftpan) >> 16); + mix[0] += (int16_t)((accm * channel->leftpan) >> 16); #else - mix += (int16_t)(accm & channel->cha); -#endif + mix[0] += (int16_t)(accm & channel->cha); + #endif + mix[1] += (int16_t)(accm & channel->chc); } - chip->mixbuff[0] = mix; + chip->mixbuff[0] = mix[0]; + chip->mixbuff[2] = mix[1]; #if OPL_QUIRK_CHANNELSAMPLEDELAY for (ii = 15; ii < 18; ii++) @@ -1139,7 +1154,8 @@ void OPL3_Generate(opl3_chip *chip, int16_t *buf) } #endif - buf[0] = OPL3_ClipSample(chip->mixbuff[0]); + buf4[0] = OPL3_ClipSample(chip->mixbuff[0]); + buf4[2] = OPL3_ClipSample(chip->mixbuff[2]); #if OPL_QUIRK_CHANNELSAMPLEDELAY for (ii = 18; ii < 33; ii++) @@ -1148,7 +1164,7 @@ void OPL3_Generate(opl3_chip *chip, int16_t *buf) } #endif - mix = 0; + mix[0] = mix[1] = 0; for (ii = 0; ii < 18; ii++) { channel = &chip->channel[ii]; @@ -1156,12 +1172,14 @@ void OPL3_Generate(opl3_chip *chip, int16_t *buf) out = channel->out; accm = *out[0] + *out[1] + *out[2] + *out[3]; #if OPL_ENABLE_STEREOEXT - mix += (int16_t)((accm * channel->rightpan) >> 16); + mix[0] += (int16_t)((accm * channel->rightpan) >> 16); #else - mix += (int16_t)(accm & channel->chb); -#endif + mix[0] += (int16_t)(accm & channel->chb); + #endif + mix[1] += (int16_t)(accm & channel->chd); } - chip->mixbuff[1] = mix; + chip->mixbuff[1] = mix[0]; + chip->mixbuff[3] = mix[1]; #if OPL_QUIRK_CHANNELSAMPLEDELAY for (ii = 33; ii < 36; ii++) @@ -1236,22 +1254,44 @@ void OPL3_Generate(opl3_chip *chip, int16_t *buf) chip->writebuf_samplecnt++; } -void OPL3_GenerateResampled(opl3_chip *chip, int16_t *buf) +void OPL3_Generate(opl3_chip *chip, int16_t *buf) +{ + int16_t samples[4]; + OPL3_Generate4Ch(chip, samples); + buf[0] = samples[0]; + buf[1] = samples[1]; +} + +void OPL3_Generate4ChResampled(opl3_chip *chip, int16_t *buf4) { while (chip->samplecnt >= chip->rateratio) { chip->oldsamples[0] = chip->samples[0]; chip->oldsamples[1] = chip->samples[1]; - OPL3_Generate(chip, chip->samples); + chip->oldsamples[2] = chip->samples[2]; + chip->oldsamples[3] = chip->samples[3]; + OPL3_Generate4Ch(chip, chip->samples); chip->samplecnt -= chip->rateratio; } - buf[0] = (int16_t)((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt) - + chip->samples[0] * chip->samplecnt) / chip->rateratio); - buf[1] = (int16_t)((chip->oldsamples[1] * (chip->rateratio - chip->samplecnt) - + chip->samples[1] * chip->samplecnt) / chip->rateratio); + buf4[0] = (int16_t)((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt) + + chip->samples[0] * chip->samplecnt) / chip->rateratio); + buf4[1] = (int16_t)((chip->oldsamples[1] * (chip->rateratio - chip->samplecnt) + + chip->samples[1] * chip->samplecnt) / chip->rateratio); + buf4[2] = (int16_t)((chip->oldsamples[2] * (chip->rateratio - chip->samplecnt) + + chip->samples[2] * chip->samplecnt) / chip->rateratio); + buf4[3] = (int16_t)((chip->oldsamples[3] * (chip->rateratio - chip->samplecnt) + + chip->samples[3] * chip->samplecnt) / chip->rateratio); chip->samplecnt += 1 << RSM_FRAC; } +void OPL3_GenerateResampled(opl3_chip *chip, int16_t *buf) +{ + int16_t samples[4]; + OPL3_Generate4ChResampled(chip, samples); + buf[0] = samples[0]; + buf[1] = samples[1]; +} + void OPL3_Reset(opl3_chip *chip, uint32_t samplerate) { opl3_slot *slot; @@ -1464,9 +1504,26 @@ void OPL3_WriteRegBuffered(opl3_chip *chip, uint16_t reg, uint8_t v) chip->writebuf_last = (writebuf_last + 1) % OPL_WRITEBUF_SIZE; } +void OPL3_Generate4ChStream(opl3_chip *chip, int16_t *sndptr1, int16_t *sndptr2, uint32_t numsamples) +{ + uint_fast32_t i; + int16_t samples[4]; + + for(i = 0; i < numsamples; i++) + { + OPL3_Generate4ChResampled(chip, samples); + sndptr1[0] = samples[0]; + sndptr1[1] = samples[1]; + sndptr2[0] = samples[2]; + sndptr2[1] = samples[3]; + sndptr1 += 2; + sndptr2 += 2; + } +} + void OPL3_GenerateStream(opl3_chip *chip, int16_t *sndptr, uint32_t numsamples) { - uint32_t i; + uint_fast32_t i; for(i = 0; i < numsamples; i++) { diff --git a/extern/opl/opl3.h b/extern/opl/opl3.h index 6ad33f3e..8d515323 100644 --- a/extern/opl/opl3.h +++ b/extern/opl/opl3.h @@ -101,6 +101,7 @@ struct _opl3_channel { uint8_t alg; uint8_t ksv; uint16_t cha, chb; + uint16_t chc, chd; uint8_t ch_num; uint8_t muted; }; @@ -129,7 +130,7 @@ struct _opl3_chip { uint8_t tremoloshift; uint32_t noise; int16_t zeromod; - int32_t mixbuff[2]; + int32_t mixbuff[4]; uint8_t rm_hh_bit2; uint8_t rm_hh_bit3; uint8_t rm_hh_bit7; @@ -144,8 +145,8 @@ struct _opl3_chip { /* OPL3L */ int32_t rateratio; int32_t samplecnt; - int16_t oldsamples[2]; - int16_t samples[2]; + int16_t oldsamples[4]; + int16_t samples[4]; uint64_t writebuf_samplecnt; uint32_t writebuf_cur; @@ -161,6 +162,10 @@ void OPL3_WriteReg(opl3_chip *chip, uint16_t reg, uint8_t v); void OPL3_WriteRegBuffered(opl3_chip *chip, uint16_t reg, uint8_t v); void OPL3_GenerateStream(opl3_chip *chip, int16_t *sndptr, uint32_t numsamples); +void OPL3_Generate4Ch(opl3_chip *chip, int16_t *buf4); +void OPL3_Generate4ChResampled(opl3_chip *chip, int16_t *buf4); +void OPL3_Generate4ChStream(opl3_chip *chip, int16_t *sndptr1, int16_t *sndptr2, uint32_t numsamples); + #ifdef __cplusplus } #endif diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index e997a20b..fc31c013 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -160,12 +160,12 @@ const int orderedOpsL[4]={ #define ADDR_LR_FB_ALG 0xc0 void DivPlatformOPL::acquire_nuked(short** buf, size_t len) { - static short o[2]; - static int os[2]; + static short o[4]; + static int os[4]; static ymfm::ymfm_output<2> aOut; for (size_t h=0; h=0) { adpcmB->clock(); @@ -225,6 +228,12 @@ void DivPlatformOPL::acquire_nuked(short** buf, size_t len) { if (fm.channel[i].out[1]!=NULL) { oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[1]; } + if (fm.channel[i].out[2]!=NULL) { + oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[2]; + } + if (fm.channel[i].out[3]!=NULL) { + oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[3]; + } oscBuf[i]->data[oscBuf[i]->needle]<<=1; oscBuf[i]->needle++; } @@ -244,6 +253,12 @@ void DivPlatformOPL::acquire_nuked(short** buf, size_t len) { if (fm.channel[i].out[1]!=NULL) { oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[1]; } + if (fm.channel[i].out[2]!=NULL) { + oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[2]; + } + if (fm.channel[i].out[3]!=NULL) { + oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[3]; + } oscBuf[i]->data[oscBuf[i]->needle]<<=1; oscBuf[i]->needle++; } @@ -254,10 +269,18 @@ void DivPlatformOPL::acquire_nuked(short** buf, size_t len) { if (os[1]<-32768) os[1]=-32768; if (os[1]>32767) os[1]=32767; + + if (os[2]<-32768) os[2]=-32768; + if (os[2]>32767) os[2]=32767; + + if (os[3]<-32768) os[3]=-32768; + if (os[3]>32767) os[3]=32767; buf[0][h]=os[0]; if (oplType==3 || oplType==759) { buf[1][h]=os[1]; + buf[2][h]=os[2]; + buf[3][h]=os[3]; } } }