Add 4-channel output support
Co-Authored-By: Kagamiin <kagamiin@riseup.net>
This commit is contained in:
@@ -151,6 +151,8 @@ typedef struct chan {
|
|||||||
uint8_t ksv;
|
uint8_t ksv;
|
||||||
uint16_t cha;
|
uint16_t cha;
|
||||||
uint16_t chb;
|
uint16_t chb;
|
||||||
|
uint16_t chc;
|
||||||
|
uint16_t chd;
|
||||||
uint8_t ch_num;
|
uint8_t ch_num;
|
||||||
} chan_t;
|
} chan_t;
|
||||||
|
|
||||||
@@ -178,7 +180,7 @@ typedef struct 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;
|
||||||
@@ -193,8 +195,8 @@ typedef struct chip {
|
|||||||
// OPL3L
|
// OPL3L
|
||||||
int32_t rateratio;
|
int32_t rateratio;
|
||||||
int32_t samplecnt;
|
int32_t samplecnt;
|
||||||
int32_t oldsamples[2];
|
int32_t oldsamples[4];
|
||||||
int32_t samples[2];
|
int32_t samples[4];
|
||||||
|
|
||||||
uint64_t wrbuf_samplecnt;
|
uint64_t wrbuf_samplecnt;
|
||||||
uint32_t wrbuf_cur;
|
uint32_t wrbuf_cur;
|
||||||
@@ -1077,10 +1079,8 @@ channel_setup_alg(chan_t *ch)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
channel_write_c0(chan_t *ch, uint8_t data)
|
channel_update_alg(chan_t *ch)
|
||||||
{
|
{
|
||||||
ch->fb = (data & 0x0e) >> 1;
|
|
||||||
ch->con = data & 0x01;
|
|
||||||
ch->alg = ch->con;
|
ch->alg = ch->con;
|
||||||
|
|
||||||
if (ch->dev->newm) {
|
if (ch->dev->newm) {
|
||||||
@@ -1096,12 +1096,24 @@ channel_write_c0(chan_t *ch, uint8_t data)
|
|||||||
channel_setup_alg(ch);
|
channel_setup_alg(ch);
|
||||||
} else
|
} else
|
||||||
channel_setup_alg(ch);
|
channel_setup_alg(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
channel_write_c0(chan_t *ch, uint8_t data)
|
||||||
|
{
|
||||||
|
ch->fb = (data & 0x0e) >> 1;
|
||||||
|
ch->con = data & 0x01;
|
||||||
|
|
||||||
if (ch->dev->newm) {
|
if (ch->dev->newm) {
|
||||||
ch->cha = ((data >> 4) & 0x01) ? ~0 : 0;
|
ch->cha = ((data >> 4) & 0x01) ? ~0 : 0;
|
||||||
ch->chb = ((data >> 5) & 0x01) ? ~0 : 0;
|
ch->chb = ((data >> 5) & 0x01) ? ~0 : 0;
|
||||||
} else
|
ch->chc = ((data >> 6) & 0x01) ? ~0 : 0;
|
||||||
|
ch->chd = ((data >> 7) & 0x01) ? ~0 : 0;
|
||||||
|
} else {
|
||||||
ch->cha = ch->chb = (uint16_t) ~0;
|
ch->cha = ch->chb = (uint16_t) ~0;
|
||||||
|
// TODO: Verify on real chip if DAC2 output is disabled in compat mode
|
||||||
|
ch->chc = ch->chd = 0;
|
||||||
|
}
|
||||||
|
|
||||||
#if OPL_ENABLE_STEREOEXT
|
#if OPL_ENABLE_STEREOEXT
|
||||||
if (!ch->dev->stereoext) {
|
if (!ch->dev->stereoext) {
|
||||||
@@ -1174,9 +1186,12 @@ channel_set_4op(nuked_t *dev, uint8_t data)
|
|||||||
if ((data >> bit) & 0x01) {
|
if ((data >> bit) & 0x01) {
|
||||||
dev->chan[chnum].chtype = ch_4op;
|
dev->chan[chnum].chtype = ch_4op;
|
||||||
dev->chan[chnum + 3].chtype = ch_4op2;
|
dev->chan[chnum + 3].chtype = ch_4op2;
|
||||||
|
channel_update_alg(&dev->chan[chnum]);
|
||||||
} else {
|
} else {
|
||||||
dev->chan[chnum].chtype = ch_2op;
|
dev->chan[chnum].chtype = ch_2op;
|
||||||
dev->chan[chnum + 3].chtype = ch_2op;
|
dev->chan[chnum + 3].chtype = ch_2op;
|
||||||
|
channel_update_alg(&dev->chan[chnum]);
|
||||||
|
channel_update_alg(&dev->chan[chnum + 3]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1337,19 +1352,20 @@ static void process_slot(slot_t *slot)
|
|||||||
slot_generate(slot);
|
slot_generate(slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
inline void
|
||||||
nuked_generate(void *priv, int32_t *bufp)
|
nuked_generate_4ch(void *priv, int32_t *buf4)
|
||||||
{
|
{
|
||||||
nuked_t *dev = (nuked_t *) priv;
|
nuked_t *dev = (nuked_t *) priv;
|
||||||
chan_t *ch;
|
chan_t *ch;
|
||||||
wrbuf_t *writebuf;
|
wrbuf_t *writebuf;
|
||||||
int16_t **out;
|
int16_t **out;
|
||||||
int32_t mix;
|
int32_t mix[2];
|
||||||
int16_t accm;
|
int16_t accm;
|
||||||
int16_t shift = 0;
|
int16_t shift = 0;
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
|
|
||||||
bufp[1] = dev->mixbuff[1];
|
buf4[1] = dev->mixbuff[1];
|
||||||
|
buf4[3] = dev->mixbuff[3];
|
||||||
|
|
||||||
#if OPL_QUIRK_CHANNELSAMPLEDELAY
|
#if OPL_QUIRK_CHANNELSAMPLEDELAY
|
||||||
for (i = 0; i < 15; i++)
|
for (i = 0; i < 15; i++)
|
||||||
@@ -1358,47 +1374,52 @@ nuked_generate(void *priv, int32_t *bufp)
|
|||||||
#endif
|
#endif
|
||||||
process_slot(&dev->slot[i]);
|
process_slot(&dev->slot[i]);
|
||||||
|
|
||||||
mix = 0;
|
mix[0] = mix[1] = 0;
|
||||||
|
|
||||||
for (i = 0; i < 18; i++) {
|
for (i = 0; i < 18; i++) {
|
||||||
ch = &dev->chan[i];
|
ch = &dev->chan[i];
|
||||||
out = ch->out;
|
out = ch->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 * ch->leftpan) >> 16);
|
mix[0] += (int16_t)((accm * ch->leftpan) >> 16);
|
||||||
#else
|
#else
|
||||||
mix += (int16_t) (accm & ch->cha);
|
mix[0] += (int16_t) (accm & ch->cha);
|
||||||
#endif
|
#endif
|
||||||
|
mix[1] += (int16_t) (accm & ch->chc);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->mixbuff[0] = mix;
|
dev->mixbuff[0] = mix[0];
|
||||||
|
dev->mixbuff[2] = mix[1];
|
||||||
|
|
||||||
#if OPL_QUIRK_CHANNELSAMPLEDELAY
|
#if OPL_QUIRK_CHANNELSAMPLEDELAY
|
||||||
for (i = 15; i < 18; i++)
|
for (i = 15; i < 18; i++)
|
||||||
process_slot(&dev->slot[i]);
|
process_slot(&dev->slot[i]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bufp[0] = dev->mixbuff[0];
|
buf4[0] = dev->mixbuff[0];
|
||||||
|
buf4[2] = dev->mixbuff[2];
|
||||||
|
|
||||||
#if OPL_QUIRK_CHANNELSAMPLEDELAY
|
#if OPL_QUIRK_CHANNELSAMPLEDELAY
|
||||||
for (i = 18; i < 33; i++)
|
for (i = 18; i < 33; i++)
|
||||||
process_slot(&dev->slot[i]);
|
process_slot(&dev->slot[i]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
mix = 0;
|
mix[0] = mix[1] = 0;
|
||||||
|
|
||||||
for (i = 0; i < 18; i++) {
|
for (i = 0; i < 18; i++) {
|
||||||
ch = &dev->chan[i];
|
ch = &dev->chan[i];
|
||||||
out = ch->out;
|
out = ch->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 * ch->leftpan) >> 16);
|
mix[0] += (int16_t)((accm * ch->leftpan) >> 16);
|
||||||
#else
|
#else
|
||||||
mix += (int16_t) (accm & ch->chb);
|
mix[0] += (int16_t) (accm & ch->chb);
|
||||||
#endif
|
#endif
|
||||||
|
mix[1] += (int16_t) (accm & ch->chd);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->mixbuff[1] = mix;
|
dev->mixbuff[1] = mix[0];
|
||||||
|
dev->mixbuff[3] = mix[1];
|
||||||
|
|
||||||
#if OPL_QUIRK_CHANNELSAMPLEDELAY
|
#if OPL_QUIRK_CHANNELSAMPLEDELAY
|
||||||
for (i = 33; i < 36; i++)
|
for (i = 33; i < 36; i++)
|
||||||
@@ -1455,26 +1476,50 @@ nuked_generate(void *priv, int32_t *bufp)
|
|||||||
dev->wrbuf_samplecnt++;
|
dev->wrbuf_samplecnt++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nuked_generate(nuked_t *dev, int32_t *buf4)
|
||||||
|
{
|
||||||
|
int32_t samples[4];
|
||||||
|
nuked_generate_4ch(dev, samples);
|
||||||
|
buf4[0] = samples[0];
|
||||||
|
buf4[1] = samples[1];
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nuked_generate_resampled(nuked_t *dev, int32_t *bufp)
|
nuked_generate_4ch_resampled(nuked_t *dev, int16_t *buf4)
|
||||||
{
|
{
|
||||||
while (dev->samplecnt >= dev->rateratio) {
|
while (dev->samplecnt >= dev->rateratio) {
|
||||||
dev->oldsamples[0] = dev->samples[0];
|
dev->oldsamples[0] = dev->samples[0];
|
||||||
dev->oldsamples[1] = dev->samples[1];
|
dev->oldsamples[1] = dev->samples[1];
|
||||||
nuked_generate(dev, dev->samples);
|
dev->oldsamples[2] = dev->samples[2];
|
||||||
|
dev->oldsamples[3] = dev->samples[3];
|
||||||
|
nuked_generate_4ch(dev, dev->samples);
|
||||||
dev->samplecnt -= dev->rateratio;
|
dev->samplecnt -= dev->rateratio;
|
||||||
}
|
}
|
||||||
|
|
||||||
bufp[0] = (int32_t) ((dev->oldsamples[0] * (dev->rateratio - dev->samplecnt)
|
buf4[0] = (int32_t) ((dev->oldsamples[0] * (dev->rateratio - dev->samplecnt)
|
||||||
+ dev->samples[0] * dev->samplecnt)
|
+ dev->samples[0] * dev->samplecnt)
|
||||||
/ dev->rateratio);
|
/ dev->rateratio);
|
||||||
bufp[1] = (int32_t) ((dev->oldsamples[1] * (dev->rateratio - dev->samplecnt)
|
buf4[1] = (int32_t) ((dev->oldsamples[1] * (dev->rateratio - dev->samplecnt)
|
||||||
+ dev->samples[1] * dev->samplecnt)
|
+ dev->samples[1] * dev->samplecnt)
|
||||||
/ dev->rateratio);
|
/ dev->rateratio);
|
||||||
|
buf4[2] = (int32_t) ((dev->oldsamples[2] * (dev->rateratio - dev->samplecnt)
|
||||||
|
+ dev->samples[2] * dev->samplecnt)
|
||||||
|
/ dev->rateratio);
|
||||||
|
buf4[3] = (int32_t) ((dev->oldsamples[3] * (dev->rateratio - dev->samplecnt)
|
||||||
|
+ dev->samples[3] * dev->samplecnt)
|
||||||
|
/ dev->rateratio);
|
||||||
|
|
||||||
dev->samplecnt += 1 << RSM_FRAC;
|
dev->samplecnt += 1 << RSM_FRAC;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void nuked_generate_resampled(nuked_t *dev, int16_t *buf4)
|
||||||
|
{
|
||||||
|
int16_t samples[4];
|
||||||
|
nuked_generate_4ch_resampled(dev, samples);
|
||||||
|
buf4[0] = samples[0];
|
||||||
|
buf4[1] = samples[1];
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nuked_generate_raw(nuked_t *dev, int32_t *bufp)
|
nuked_generate_raw(nuked_t *dev, int32_t *bufp)
|
||||||
{
|
{
|
||||||
@@ -1484,10 +1529,26 @@ nuked_generate_raw(nuked_t *dev, int32_t *bufp)
|
|||||||
bufp[1] = (int32_t) dev->samples[1];
|
bufp[1] = (int32_t) dev->samples[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nuked_generate_4ch_stream(nuked_t *dev, int16_t *sndptr1, int16_t *sndptr2, uint32_t numsamples)
|
||||||
|
{
|
||||||
|
int16_t samples[4];
|
||||||
|
|
||||||
|
for (uint_fast32_t i = 0; i < numsamples; i++) {
|
||||||
|
nuked_generate_4ch_resampled(dev, samples);
|
||||||
|
sndptr1[0] = samples[0];
|
||||||
|
sndptr1[1] = samples[1];
|
||||||
|
sndptr2[0] = samples[2];
|
||||||
|
sndptr2[1] = samples[3];
|
||||||
|
sndptr1 += 2;
|
||||||
|
sndptr2 += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nuked_generate_stream(nuked_t *dev, int32_t *sndptr, uint32_t num)
|
nuked_generate_stream(nuked_t *dev, int32_t *sndptr, uint32_t num)
|
||||||
{
|
{
|
||||||
for (uint32_t i = 0; i < num; i++) {
|
for (uint_fast32_t i = 0; i < num; i++) {
|
||||||
nuked_generate_raw(dev, sndptr);
|
nuked_generate_raw(dev, sndptr);
|
||||||
sndptr += 2;
|
sndptr += 2;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user