k054539: Uncross the streams [O. Galibert]

This commit is contained in:
Olivier Galibert 2012-03-05 18:28:03 +00:00
parent 4e3ac4fb9d
commit 347ff9bce4

View File

@ -69,11 +69,7 @@ void k054539_device::static_set_interface(device_t &device, const k054539_interf
22f: enable pcm (b0), disable register ram updating (b7) 22f: enable pcm (b0), disable register ram updating (b7)
The chip has a 0x4000 bytes reverb buffer (the ram from 0x22e). The chip has a 0x4000 bytes reverb buffer (the ram from 0x22e).
The reverb delay is actually an offset in this buffer. This driver The reverb delay is actually an offset in this buffer.
uses some tricks (doubling the buffer size so that the longest
reverbs don't fold over the sound to output, and adding a space at
the end to fold back overflows in) to be able to do frame-based
rendering instead of sample-based.
*/ */
void k054539_device::init_flags(int _flags) void k054539_device::init_flags(int _flags)
@ -115,88 +111,85 @@ void k054539_device::sound_stream_update(sound_stream &stream, stream_sample_t *
}; };
int cur_reverb_pos = reverb_pos;
INT16 *rbase = (INT16 *)ram; INT16 *rbase = (INT16 *)ram;
memset(outputs[0], 0, samples*sizeof(*outputs[0])); if(!(regs[0x22f] & 1))
memset(outputs[1], 0, samples*sizeof(*outputs[1])); return;
if(!(regs[0x22f] & 1)) return; for(int sample = 0; sample != samples; sample++) {
double lval, rval;
if(!(flags & DISABLE_REVERB))
lval = rval = rbase[reverb_pos];
else
lval = rval = 0;
rbase[reverb_pos] = 0;
for(int ch=0; ch<8; ch++)
if(regs[0x22c] & (1<<ch)) {
unsigned char *base1 = regs + 0x20*ch;
unsigned char *base2 = regs + 0x200 + 0x2*ch;
channel *chan = channels + ch;
reverb_pos = (reverb_pos + samples) & 0x3fff; int delta = base1[0x00] | (base1[0x01] << 8) | (base1[0x02] << 16);
for(int ch=0; ch<8; ch++) int vol = base1[0x03];
if(regs[0x22c] & (1<<ch)) {
unsigned char *base1 = regs + 0x20*ch;
unsigned char *base2 = regs + 0x200 + 0x2*ch;
channel *chan = channels + ch;
int delta = base1[0x00] | (base1[0x01] << 8) | (base1[0x02] << 16); int bval = vol + base1[0x04];
if (bval > 255)
bval = 255;
int vol = base1[0x03]; int pan = base1[0x05];
// DJ Main: 81-87 right, 88 middle, 89-8f left
if (pan >= 0x81 && pan <= 0x8f)
pan -= 0x81;
else if (pan >= 0x11 && pan <= 0x1f)
pan -= 0x11;
else
pan = 0x18 - 0x11;
int bval = vol + base1[0x04]; double cur_gain = gain[ch];
if (bval > 255) bval = 255;
int pan = base1[0x05]; double lvol = voltab[vol] * pantab[pan] * cur_gain;
// DJ Main: 81-87 right, 88 middle, 89-8f left if (lvol > VOL_CAP)
if (pan >= 0x81 && pan <= 0x8f) lvol = VOL_CAP;
pan -= 0x81;
else
if (pan >= 0x11 && pan <= 0x1f) pan -= 0x11; else pan = 0x18 - 0x11;
double cur_gain = gain[ch]; double rvol = voltab[vol] * pantab[0xe - pan] * cur_gain;
if (rvol > VOL_CAP)
rvol = VOL_CAP;
double lvol = voltab[vol] * pantab[pan] * cur_gain; double rbvol= voltab[bval] * cur_gain / 2;
if (lvol > VOL_CAP) lvol = VOL_CAP; if (rbvol > VOL_CAP)
rbvol = VOL_CAP;
double rvol = voltab[vol] * pantab[0xe - pan] * cur_gain; int rdelta = (base1[6] | (base1[7] << 8)) >> 3;
if (rvol > VOL_CAP) rvol = VOL_CAP; rdelta = (rdelta + reverb_pos) & 0x3fff;
double rbvol= voltab[bval] * cur_gain / 2; int cur_pos = (base1[0x0c] | (base1[0x0d] << 8) | (base1[0x0e] << 16)) & rom_mask;
if (rbvol > VOL_CAP) rbvol = VOL_CAP;
int rdelta = (base1[6] | (base1[7] << 8)) >> 3;
rdelta = (rdelta + cur_reverb_pos) & 0x3fff;
int cur_pos = (base1[0x0c] | (base1[0x0d] << 8) | (base1[0x0e] << 16)) & rom_mask;
stream_sample_t *bufl = outputs[0]; int fdelta, pdelta;
stream_sample_t *bufr = outputs[1]; if(base2[0] & 0x20) {
delta = -delta;
fdelta = +0x10000;
pdelta = -1;
} else {
fdelta = -0x10000;
pdelta = +1;
}
int fdelta, pdelta; int cur_pfrac, cur_val, cur_pval;
if(base2[0] & 0x20) { if(cur_pos != chan->pos) {
delta = -delta; chan->pos = cur_pos;
fdelta = +0x10000; cur_pfrac = 0;
pdelta = -1; cur_val = 0;
} else { cur_pval = 0;
fdelta = -0x10000; } else {
pdelta = +1; cur_pfrac = chan->pfrac;
} cur_val = chan->val;
cur_pval = chan->pval;
}
int cur_pfrac, cur_val, cur_pval; switch(base2[0] & 0xc) {
if(cur_pos != chan->pos) { case 0x0: { // 8bit pcm
chan->pos = cur_pos;
cur_pfrac = 0;
cur_val = 0;
cur_pval = 0;
} else {
cur_pfrac = chan->pfrac;
cur_val = chan->val;
cur_pval = chan->pval;
}
#define UPDATE_CHANNELS \
do { \
*bufl++ += (INT16)(cur_val*lvol); \
*bufr++ += (INT16)(cur_val*rvol); \
rbase[rdelta++] += (INT16)(cur_val*rbvol); \
rdelta &= 0x3fff; \
} while(0)
switch(base2[0] & 0xc) {
case 0x0: { // 8bit pcm
for(int i=0; i<samples; i++) {
cur_pfrac += delta; cur_pfrac += delta;
while(cur_pfrac & ~0xffff) { while(cur_pfrac & ~0xffff) {
cur_pfrac += fdelta; cur_pfrac += fdelta;
@ -204,27 +197,22 @@ void k054539_device::sound_stream_update(sound_stream &stream, stream_sample_t *
cur_pval = cur_val; cur_pval = cur_val;
cur_val = (INT16)(rom[cur_pos] << 8); cur_val = (INT16)(rom[cur_pos] << 8);
if(cur_val == (INT16)0x8000 && (base2[1] & 1)) {
cur_pos = (base1[0x08] | (base1[0x09] << 8) | (base1[0x0a] << 16)) & rom_mask;
cur_val = (INT16)(rom[cur_pos] << 8);
}
if(cur_val == (INT16)0x8000) { if(cur_val == (INT16)0x8000) {
if(base2[1] & 1) {
cur_pos = (base1[0x08] | (base1[0x09] << 8) | (base1[0x0a] << 16)) & rom_mask;
cur_val = (INT16)(rom[cur_pos] << 8);
if(cur_val != (INT16)0x8000)
continue;
}
keyoff(ch); keyoff(ch);
goto end_channel_0; cur_val = 0;
break;
} }
} }
break;
UPDATE_CHANNELS;
} }
end_channel_0:
break;
}
case 0x4: { // 16bit pcm lsb first
pdelta <<= 1;
for(int i=0; i<samples; i++) { case 0x4: { // 16bit pcm lsb first
pdelta <<= 1;
cur_pfrac += delta; cur_pfrac += delta;
while(cur_pfrac & ~0xffff) { while(cur_pfrac & ~0xffff) {
cur_pfrac += fdelta; cur_pfrac += fdelta;
@ -232,32 +220,27 @@ void k054539_device::sound_stream_update(sound_stream &stream, stream_sample_t *
cur_pval = cur_val; cur_pval = cur_val;
cur_val = (INT16)(rom[cur_pos] | rom[cur_pos+1]<<8); cur_val = (INT16)(rom[cur_pos] | rom[cur_pos+1]<<8);
if(cur_val == (INT16)0x8000 && (base2[1] & 1)) {
cur_pos = (base1[0x08] | (base1[0x09] << 8) | (base1[0x0a] << 16)) & rom_mask;
cur_val = (INT16)(rom[cur_pos] | rom[cur_pos+1]<<8);
}
if(cur_val == (INT16)0x8000) { if(cur_val == (INT16)0x8000) {
if(base2[1] & 1) {
cur_pos = (base1[0x08] | (base1[0x09] << 8) | (base1[0x0a] << 16)) & rom_mask;
cur_val = (INT16)(rom[cur_pos] | rom[cur_pos+1]<<8);
if(cur_val != (INT16)0x8000)
continue;
}
keyoff(ch); keyoff(ch);
goto end_channel_4; cur_val = 0;
break;
} }
} }
break;
UPDATE_CHANNELS;
}
end_channel_4:
break;
}
case 0x8: { // 4bit dpcm
cur_pos <<= 1;
cur_pfrac <<= 1;
if(cur_pfrac & 0x10000) {
cur_pfrac &= 0xffff;
cur_pos |= 1;
} }
for(int i=0; i<samples; i++) { case 0x8: { // 4bit dpcm
cur_pos <<= 1;
cur_pfrac <<= 1;
if(cur_pfrac & 0x10000) {
cur_pfrac &= 0xffff;
cur_pos |= 1;
}
cur_pfrac += delta; cur_pfrac += delta;
while(cur_pfrac & ~0xffff) { while(cur_pfrac & ~0xffff) {
cur_pfrac += fdelta; cur_pfrac += fdelta;
@ -265,17 +248,15 @@ void k054539_device::sound_stream_update(sound_stream &stream, stream_sample_t *
cur_pval = cur_val; cur_pval = cur_val;
cur_val = rom[cur_pos>>1]; cur_val = rom[cur_pos>>1];
if(cur_val == 0x88) { if(cur_val == 0x88 && (base2[1] & 1)) {
if(base2[1] & 1) { cur_pos = ((base1[0x08] | (base1[0x09] << 8) | (base1[0x0a] << 16)) & rom_mask) << 1;
cur_pos = ((base1[0x08] | (base1[0x09] << 8) | (base1[0x0a] << 16)) & rom_mask) << 1; cur_val = rom[cur_pos>>1];
cur_val = rom[cur_pos>>1]; }
if(cur_val != 0x88) if(cur_val == 0x88) {
goto next_iter; keyoff(ch);
} cur_val = 0;
keyoff(ch); break;
goto end_channel_8;
} }
next_iter:
if(cur_pos & 1) if(cur_pos & 1)
cur_val >>= 4; cur_val >>= 4;
else else
@ -287,46 +268,35 @@ void k054539_device::sound_stream_update(sound_stream &stream, stream_sample_t *
cur_val = 32767; cur_val = 32767;
} }
UPDATE_CHANNELS; cur_pfrac >>= 1;
if(cur_pos & 1)
cur_pfrac |= 0x8000;
cur_pos >>= 1;
break;
}
default:
LOG(("Unknown sample type %x for channel %d\n", base2[0] & 0xc, ch));
break;
}
lval += cur_val * lvol;
rval += cur_val * rvol;
rbase[(rdelta + reverb_pos) & 0x1fff] += INT16(cur_val*rbvol);
chan->pos = cur_pos;
chan->pfrac = cur_pfrac;
chan->pval = cur_pval;
chan->val = cur_val;
if(regupdate()) {
base1[0x0c] = cur_pos & 0xff;
base1[0x0d] = cur_pos>> 8 & 0xff;
base1[0x0e] = cur_pos>>16 & 0xff;
} }
end_channel_8:
cur_pfrac >>= 1;
if(cur_pos & 1)
cur_pfrac |= 0x8000;
cur_pos >>= 1;
break;
} }
default: reverb_pos = (reverb_pos + 1) & 0x1fff;
LOG(("Unknown sample type %x for channel %d\n", base2[0] & 0xc, ch)); outputs[0][sample] = INT16(lval);
break; outputs[1][sample] = INT16(rval);
}
chan->pos = cur_pos;
chan->pfrac = cur_pfrac;
chan->pval = cur_pval;
chan->val = cur_val;
if(regupdate()) {
base1[0x0c] = cur_pos & 0xff;
base1[0x0d] = cur_pos>> 8 & 0xff;
base1[0x0e] = cur_pos>>16 & 0xff;
}
}
//* drivers should be given the option to disable reverb when things go terribly wrong
if(!(flags & DISABLE_REVERB))
{
for(int i=0; i<samples; i++) {
INT16 val = rbase[(i+reverb_pos) & 0x3fff];
outputs[0][i] += val;
outputs[1][i] += val;
}
} }
if(cur_reverb_pos + samples > 0x4000) {
int i = 0x4000 - cur_reverb_pos;
memset(rbase + cur_reverb_pos, 0, i*2);
memset(rbase, 0, (samples-i)*2);
} else
memset(rbase + cur_reverb_pos, 0, samples*2);
} }
@ -342,11 +312,10 @@ void k054539_device::init_chip()
memset(posreg_latch, 0, sizeof(posreg_latch)); //* memset(posreg_latch, 0, sizeof(posreg_latch)); //*
flags |= UPDATE_AT_KEYON; //* make it default until proven otherwise flags |= UPDATE_AT_KEYON; //* make it default until proven otherwise
// Real size of 0x4000, the addon is to simplify the reverb buffer computations ram = auto_alloc_array(machine(), unsigned char, 0x4000);
ram = auto_alloc_array(machine(), unsigned char, 0x4000*2+clock()/50*2);
reverb_pos = 0; reverb_pos = 0;
cur_ptr = 0; cur_ptr = 0;
memset(ram, 0, 0x4000*2+clock()/50*2); memset(ram, 0, 0x4000);
const memory_region *reg = (rgnoverride != NULL) ? machine().region(rgnoverride) : region(); const memory_region *reg = (rgnoverride != NULL) ? machine().region(rgnoverride) : region();
rom = *reg; rom = *reg;