OPL: quad output

now that we have this new dispatch output method
This commit is contained in:
tildearrow 2023-01-04 18:30:29 -05:00
parent 6c834524aa
commit fd9b1dd0f5
3 changed files with 118 additions and 33 deletions

105
extern/opl/opl3.c vendored
View file

@ -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; channel->alg = channel->con;
if (channel->chip->newm) if (channel->chip->newm)
{ {
@ -974,14 +972,25 @@ static void OPL3_ChannelWriteC0(opl3_channel *channel, uint8_t data)
{ {
OPL3_ChannelSetupAlg(channel); 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) if (channel->chip->newm)
{ {
channel->cha = ((data >> 4) & 0x01) ? ~0 : 0; channel->cha = ((data >> 4) & 0x01) ? ~0 : 0;
channel->chb = ((data >> 5) & 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 else
{ {
channel->cha = channel->chb = (uint16_t)~0; 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 OPL_ENABLE_STEREOEXT
if (!channel->chip->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].chtype = ch_4op;
chip->channel[chnum + 3].chtype = ch_4op2; chip->channel[chnum + 3].chtype = ch_4op2;
OPL3_ChannelUpdateAlg(&chip->channel[chnum]);
} }
else else
{ {
chip->channel[chnum].chtype = ch_2op; chip->channel[chnum].chtype = ch_2op;
chip->channel[chnum + 3].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); 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_channel *channel;
opl3_writebuf *writebuf; opl3_writebuf *writebuf;
int16_t **out; int16_t **out;
int32_t mix; int32_t mix[2];
uint8_t ii; uint8_t ii;
int16_t accm; int16_t accm;
uint8_t shift = 0; 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 #if OPL_QUIRK_CHANNELSAMPLEDELAY
for (ii = 0; ii < 15; ii++) for (ii = 0; ii < 15; ii++)
@ -1117,7 +1130,7 @@ void OPL3_Generate(opl3_chip *chip, int16_t *buf)
OPL3_ProcessSlot(&chip->slot[ii]); OPL3_ProcessSlot(&chip->slot[ii]);
} }
mix = 0; mix[0] = mix[1] = 0;
for (ii = 0; ii < 18; ii++) for (ii = 0; ii < 18; ii++)
{ {
channel = &chip->channel[ii]; channel = &chip->channel[ii];
@ -1125,12 +1138,14 @@ void OPL3_Generate(opl3_chip *chip, int16_t *buf)
out = channel->out; out = channel->out;
accm = *out[0] + *out[1] + *out[2] + *out[3]; accm = *out[0] + *out[1] + *out[2] + *out[3];
#if OPL_ENABLE_STEREOEXT #if OPL_ENABLE_STEREOEXT
mix += (int16_t)((accm * channel->leftpan) >> 16); mix[0] += (int16_t)((accm * channel->leftpan) >> 16);
#else #else
mix += (int16_t)(accm & channel->cha); mix[0] += (int16_t)(accm & channel->cha);
#endif #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 #if OPL_QUIRK_CHANNELSAMPLEDELAY
for (ii = 15; ii < 18; ii++) for (ii = 15; ii < 18; ii++)
@ -1139,7 +1154,8 @@ void OPL3_Generate(opl3_chip *chip, int16_t *buf)
} }
#endif #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 #if OPL_QUIRK_CHANNELSAMPLEDELAY
for (ii = 18; ii < 33; ii++) for (ii = 18; ii < 33; ii++)
@ -1148,7 +1164,7 @@ void OPL3_Generate(opl3_chip *chip, int16_t *buf)
} }
#endif #endif
mix = 0; mix[0] = mix[1] = 0;
for (ii = 0; ii < 18; ii++) for (ii = 0; ii < 18; ii++)
{ {
channel = &chip->channel[ii]; channel = &chip->channel[ii];
@ -1156,12 +1172,14 @@ void OPL3_Generate(opl3_chip *chip, int16_t *buf)
out = channel->out; out = channel->out;
accm = *out[0] + *out[1] + *out[2] + *out[3]; accm = *out[0] + *out[1] + *out[2] + *out[3];
#if OPL_ENABLE_STEREOEXT #if OPL_ENABLE_STEREOEXT
mix += (int16_t)((accm * channel->rightpan) >> 16); mix[0] += (int16_t)((accm * channel->rightpan) >> 16);
#else #else
mix += (int16_t)(accm & channel->chb); mix[0] += (int16_t)(accm & channel->chb);
#endif #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 #if OPL_QUIRK_CHANNELSAMPLEDELAY
for (ii = 33; ii < 36; ii++) for (ii = 33; ii < 36; ii++)
@ -1236,22 +1254,44 @@ void OPL3_Generate(opl3_chip *chip, int16_t *buf)
chip->writebuf_samplecnt++; 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) while (chip->samplecnt >= chip->rateratio)
{ {
chip->oldsamples[0] = chip->samples[0]; chip->oldsamples[0] = chip->samples[0];
chip->oldsamples[1] = chip->samples[1]; 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; chip->samplecnt -= chip->rateratio;
} }
buf[0] = (int16_t)((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt) buf4[0] = (int16_t)((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt)
+ chip->samples[0] * chip->samplecnt) / chip->rateratio); + chip->samples[0] * chip->samplecnt) / chip->rateratio);
buf[1] = (int16_t)((chip->oldsamples[1] * (chip->rateratio - chip->samplecnt) buf4[1] = (int16_t)((chip->oldsamples[1] * (chip->rateratio - chip->samplecnt)
+ chip->samples[1] * chip->samplecnt) / chip->rateratio); + 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; 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) void OPL3_Reset(opl3_chip *chip, uint32_t samplerate)
{ {
opl3_slot *slot; 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; 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) 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++) for(i = 0; i < numsamples; i++)
{ {

11
extern/opl/opl3.h vendored
View file

@ -101,6 +101,7 @@ struct _opl3_channel {
uint8_t alg; uint8_t alg;
uint8_t ksv; uint8_t ksv;
uint16_t cha, chb; uint16_t cha, chb;
uint16_t chc, chd;
uint8_t ch_num; uint8_t ch_num;
uint8_t muted; uint8_t muted;
}; };
@ -129,7 +130,7 @@ struct _opl3_chip {
uint8_t tremoloshift; uint8_t tremoloshift;
uint32_t noise; uint32_t noise;
int16_t zeromod; int16_t zeromod;
int32_t mixbuff[2]; int32_t mixbuff[4];
uint8_t rm_hh_bit2; uint8_t rm_hh_bit2;
uint8_t rm_hh_bit3; uint8_t rm_hh_bit3;
uint8_t rm_hh_bit7; uint8_t rm_hh_bit7;
@ -144,8 +145,8 @@ struct _opl3_chip {
/* OPL3L */ /* OPL3L */
int32_t rateratio; int32_t rateratio;
int32_t samplecnt; int32_t samplecnt;
int16_t oldsamples[2]; int16_t oldsamples[4];
int16_t samples[2]; int16_t samples[4];
uint64_t writebuf_samplecnt; uint64_t writebuf_samplecnt;
uint32_t writebuf_cur; 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_WriteRegBuffered(opl3_chip *chip, uint16_t reg, uint8_t v);
void OPL3_GenerateStream(opl3_chip *chip, int16_t *sndptr, uint32_t numsamples); 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 #ifdef __cplusplus
} }
#endif #endif

View file

@ -160,12 +160,12 @@ const int orderedOpsL[4]={
#define ADDR_LR_FB_ALG 0xc0 #define ADDR_LR_FB_ALG 0xc0
void DivPlatformOPL::acquire_nuked(short** buf, size_t len) { void DivPlatformOPL::acquire_nuked(short** buf, size_t len) {
static short o[2]; static short o[4];
static int os[2]; static int os[4];
static ymfm::ymfm_output<2> aOut; static ymfm::ymfm_output<2> aOut;
for (size_t h=0; h<len; h++) { for (size_t h=0; h<len; h++) {
os[0]=0; os[1]=0; os[0]=0; os[1]=0; os[2]=0; os[3]=0;
if (!writes.empty() && --delay<0) { if (!writes.empty() && --delay<0) {
delay=1; delay=1;
QueuedWrite& w=writes.front(); QueuedWrite& w=writes.front();
@ -194,11 +194,14 @@ void DivPlatformOPL::acquire_nuked(short** buf, size_t len) {
} }
if (downsample) { if (downsample) {
OPL3_GenerateResampled(&fm,o); OPL3_Generate4ChResampled(&fm,o);
} else { } else {
OPL3_Generate(&fm,o); OPL3_Generate4Ch(&fm,o);
} }
os[0]+=o[0]; os[1]+=o[1]; os[0]+=o[0];
os[1]+=o[1];
os[2]+=o[2];
os[3]+=o[3];
if (adpcmChan>=0) { if (adpcmChan>=0) {
adpcmB->clock(); adpcmB->clock();
@ -225,6 +228,12 @@ void DivPlatformOPL::acquire_nuked(short** buf, size_t len) {
if (fm.channel[i].out[1]!=NULL) { if (fm.channel[i].out[1]!=NULL) {
oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[1]; 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]->data[oscBuf[i]->needle]<<=1;
oscBuf[i]->needle++; oscBuf[i]->needle++;
} }
@ -244,6 +253,12 @@ void DivPlatformOPL::acquire_nuked(short** buf, size_t len) {
if (fm.channel[i].out[1]!=NULL) { if (fm.channel[i].out[1]!=NULL) {
oscBuf[i]->data[oscBuf[i]->needle]+=*fm.channel[ch].out[1]; 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]->data[oscBuf[i]->needle]<<=1;
oscBuf[i]->needle++; 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]<-32768) os[1]=-32768;
if (os[1]>32767) os[1]=32767; 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]; buf[0][h]=os[0];
if (oplType==3 || oplType==759) { if (oplType==3 || oplType==759) {
buf[1][h]=os[1]; buf[1][h]=os[1];
buf[2][h]=os[2];
buf[3][h]=os[3];
} }
} }
} }