OPL: quad output
now that we have this new dispatch output method
This commit is contained in:
parent
6c834524aa
commit
fd9b1dd0f5
105
extern/opl/opl3.c
vendored
105
extern/opl/opl3.c
vendored
|
@ -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
11
extern/opl/opl3.h
vendored
|
@ -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
|
||||||
|
|
|
@ -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];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue