mirror of
https://github.com/holub/mame
synced 2025-06-22 20:38:50 +03:00
Merge pull request #1254 from superctr/c352_improvement
Namco C352 improvements
This commit is contained in:
commit
2d198239db
@ -1,9 +1,10 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:R. Belmont
|
||||
// copyright-holders:R. Belmont, superctr
|
||||
/*
|
||||
c352.c - Namco C352 custom PCM chip emulation
|
||||
v1.2
|
||||
v2.0
|
||||
By R. Belmont
|
||||
Rewritten and improved by superctr
|
||||
Additional code by cync and the hoot development team
|
||||
|
||||
Thanks to Cap of VivaNonno for info and The_Author for preliminary reverse-engineering
|
||||
@ -13,14 +14,6 @@
|
||||
Supports 8-bit linear and 8-bit muLaw samples
|
||||
Output: digital, 16 bit, 4 channels
|
||||
Output sample rate is the input clock / (288 * 2).
|
||||
|
||||
superctr: The clock divider appears to be configurable for each system.
|
||||
Below is a list of the divider values followed by the systems that use it.
|
||||
|
||||
* 228: System 11.
|
||||
* 288: System 22, Super 22, NB-1/2, ND-1, FL.
|
||||
* 296: System 23, Super 23.
|
||||
* 332: System 12.
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
@ -58,405 +51,195 @@ void c352_device::static_set_divider(device_t &device, int setting)
|
||||
c352.m_divider = setting;
|
||||
}
|
||||
|
||||
|
||||
// noise generator
|
||||
int c352_device::get_mseq_bit()
|
||||
void c352_device::fetch_sample(c352_voice_t* v)
|
||||
{
|
||||
unsigned int mask = (1 << (7 - 1));
|
||||
unsigned int reg = m_mseq_reg;
|
||||
unsigned int bit = reg & (1 << (17 - 1));
|
||||
v->last_sample = v->sample;
|
||||
|
||||
if (bit)
|
||||
{
|
||||
reg = ((reg ^ mask) << 1) | 1;
|
||||
if(v->flags & C352_FLG_NOISE)
|
||||
{
|
||||
m_random = (m_random>>1) ^ ((-(m_random&1)) & 0xfff6);
|
||||
v->sample = m_random;
|
||||
}
|
||||
else
|
||||
{
|
||||
reg = reg << 1;
|
||||
}
|
||||
char s;
|
||||
|
||||
m_mseq_reg = reg;
|
||||
s = (char)read_byte(v->pos);
|
||||
|
||||
return (reg & 1);
|
||||
}
|
||||
if(v->flags & C352_FLG_MULAW)
|
||||
v->sample = m_mulaw_table[(unsigned char)s];
|
||||
else
|
||||
v->sample = s<<8;
|
||||
|
||||
void c352_device::mix_one_channel(unsigned long ch, long sample_count)
|
||||
{
|
||||
int i;
|
||||
unsigned short pos = v->pos&0xffff;
|
||||
|
||||
signed short sample, nextsample;
|
||||
signed short noisebuf;
|
||||
UINT16 noisecnt;
|
||||
INT32 frequency, delta, offset, cnt, flag;
|
||||
UINT32 bank;
|
||||
UINT32 pos;
|
||||
if((v->flags & C352_FLG_LOOP) && v->flags & C352_FLG_REVERSE)
|
||||
{
|
||||
// backwards>forwards
|
||||
if((v->flags & C352_FLG_LDIR) && pos == v->wave_loop)
|
||||
v->flags &= ~C352_FLG_LDIR;
|
||||
// forwards>backwards
|
||||
else if(!(v->flags & C352_FLG_LDIR) && pos == v->wave_end)
|
||||
v->flags |= C352_FLG_LDIR;
|
||||
|
||||
frequency = m_c352_ch[ch].pitch;
|
||||
delta=frequency;
|
||||
|
||||
pos = m_c352_ch[ch].current_addr; // sample pointer
|
||||
offset = m_c352_ch[ch].pos; // 16.16 fixed-point offset into the sample
|
||||
flag = m_c352_ch[ch].flag;
|
||||
bank = m_c352_ch[ch].bank << 16;
|
||||
|
||||
noisecnt = m_c352_ch[ch].noisecnt;
|
||||
noisebuf = m_c352_ch[ch].noisebuf;
|
||||
|
||||
for(i = 0 ; (i < sample_count) && (flag & C352_FLG_BUSY) ; i++)
|
||||
{
|
||||
offset += delta;
|
||||
cnt = (offset>>16)&0x7fff;
|
||||
if (cnt) // if there is a whole sample part, chop it off now that it's been applied
|
||||
{
|
||||
offset &= 0xffff;
|
||||
}
|
||||
|
||||
if (pos > 0x1000000)
|
||||
{
|
||||
m_c352_ch[ch].flag &= ~C352_FLG_BUSY;
|
||||
return;
|
||||
}
|
||||
|
||||
sample = (char)read_byte(pos);
|
||||
nextsample = (char)read_byte(pos+cnt);
|
||||
|
||||
// sample is muLaw, not 8-bit linear (Fighting Layer uses this extensively)
|
||||
if (flag & C352_FLG_MULAW)
|
||||
{
|
||||
sample = m_mulaw_table[(unsigned char)sample];
|
||||
nextsample = m_mulaw_table[(unsigned char)nextsample];
|
||||
}
|
||||
v->pos += (v->flags&C352_FLG_LDIR) ? -1 : 1;
|
||||
}
|
||||
else if(pos == v->wave_end)
|
||||
{
|
||||
if((v->flags & C352_FLG_LINK) && (v->flags & C352_FLG_LOOP))
|
||||
{
|
||||
v->pos = (v->wave_start<<16) | v->wave_loop;
|
||||
v->flags |= C352_FLG_LOOPHIST;
|
||||
}
|
||||
else if(v->flags & C352_FLG_LOOP)
|
||||
{
|
||||
v->pos = (v->pos&0xff0000) | v->wave_loop;
|
||||
v->flags |= C352_FLG_LOOPHIST;
|
||||
}
|
||||
else
|
||||
{
|
||||
v->flags |= C352_FLG_KEYOFF;
|
||||
v->flags &= ~C352_FLG_BUSY;
|
||||
v->sample=0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sample <<= 8;
|
||||
nextsample <<= 8;
|
||||
}
|
||||
|
||||
// play noise instead of sample data
|
||||
if (flag & C352_FLG_NOISE)
|
||||
{
|
||||
int noise_level = 0x8000;
|
||||
sample = m_c352_ch[ch].noise = (m_c352_ch[ch].noise << 1) | get_mseq_bit();
|
||||
sample = (sample & (noise_level - 1)) - (noise_level >> 1);
|
||||
if (sample > 0x7f)
|
||||
{
|
||||
sample = 0x7f;
|
||||
}
|
||||
else if (sample < 0)
|
||||
{
|
||||
sample = 0xff;
|
||||
}
|
||||
sample = m_mulaw_table[(unsigned char)sample];
|
||||
|
||||
if ( (pos+cnt) == pos )
|
||||
{
|
||||
noisebuf += sample;
|
||||
noisecnt++;
|
||||
sample = noisebuf / noisecnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( noisecnt )
|
||||
{
|
||||
sample = noisebuf / noisecnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
sample = m_mulaw_table[0x7f]; // Nearest sound(s) is here.
|
||||
}
|
||||
noisebuf = 0;
|
||||
noisecnt = ( flag & C352_FLG_FILTER ) ? 0 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
// apply linear interpolation
|
||||
if ( (flag & (C352_FLG_FILTER | C352_FLG_NOISE)) == 0 )
|
||||
{
|
||||
sample = (short)(sample + ((nextsample-sample) * (((double)(0x0000ffff&offset) )/0x10000)));
|
||||
}
|
||||
|
||||
if ( flag & C352_FLG_PHASEFL )
|
||||
{
|
||||
m_channel_l[i] += ((-sample * m_c352_ch[ch].vol_l)>>8);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_channel_l[i] += ((sample * m_c352_ch[ch].vol_l)>>8);
|
||||
}
|
||||
|
||||
if ( flag & C352_FLG_PHASEFR )
|
||||
{
|
||||
m_channel_r[i] += ((-sample * m_c352_ch[ch].vol_r)>>8);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_channel_r[i] += ((sample * m_c352_ch[ch].vol_r)>>8);
|
||||
}
|
||||
|
||||
if ( flag & C352_FLG_PHASERL )
|
||||
{
|
||||
m_channel_l2[i] += ((-sample * m_c352_ch[ch].vol_l2)>>8);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_channel_l2[i] += ((sample * m_c352_ch[ch].vol_l2)>>8);
|
||||
}
|
||||
m_channel_r2[i] += ((sample * m_c352_ch[ch].vol_r2)>>8);
|
||||
|
||||
if ( (flag & C352_FLG_REVERSE) && (flag & C352_FLG_LOOP) )
|
||||
{
|
||||
if ( !(flag & C352_FLG_LDIR) )
|
||||
{
|
||||
pos += cnt;
|
||||
if (
|
||||
(((pos&0xFFFF) > m_c352_ch[ch].end_addr) && ((pos&0xFFFF) < m_c352_ch[ch].start) && (m_c352_ch[ch].start > m_c352_ch[ch].end_addr) ) ||
|
||||
(((pos&0xFFFF) > m_c352_ch[ch].end_addr) && ((pos&0xFFFF) > m_c352_ch[ch].start) && (m_c352_ch[ch].start < m_c352_ch[ch].end_addr) ) ||
|
||||
((pos > (bank|0xFFFF)) && (m_c352_ch[ch].end_addr == 0xFFFF))
|
||||
)
|
||||
{
|
||||
m_c352_ch[ch].flag |= C352_FLG_LDIR;
|
||||
m_c352_ch[ch].flag |= C352_FLG_LOOPHIST;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pos -= cnt;
|
||||
if (
|
||||
(((pos&0xFFFF) < m_c352_ch[ch].repeat) && ((pos&0xFFFF) < m_c352_ch[ch].end_addr) && (m_c352_ch[ch].end_addr > m_c352_ch[ch].start) ) ||
|
||||
(((pos&0xFFFF) < m_c352_ch[ch].repeat) && ((pos&0xFFFF) > m_c352_ch[ch].end_addr) && (m_c352_ch[ch].end_addr < m_c352_ch[ch].start) ) ||
|
||||
((pos < bank) && (m_c352_ch[ch].repeat == 0x0000))
|
||||
)
|
||||
{
|
||||
m_c352_ch[ch].flag &= ~C352_FLG_LDIR;
|
||||
m_c352_ch[ch].flag |= C352_FLG_LOOPHIST;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( flag & C352_FLG_REVERSE )
|
||||
{
|
||||
pos -= cnt;
|
||||
if (
|
||||
(((pos&0xFFFF) < m_c352_ch[ch].end_addr) && ((pos&0xFFFF) < m_c352_ch[ch].start) && (m_c352_ch[ch].start > m_c352_ch[ch].end_addr) ) ||
|
||||
(((pos&0xFFFF) < m_c352_ch[ch].end_addr) && ((pos&0xFFFF) > m_c352_ch[ch].start) && (m_c352_ch[ch].start < m_c352_ch[ch].end_addr) ) ||
|
||||
((pos < bank) && (m_c352_ch[ch].end_addr == 0x0000))
|
||||
)
|
||||
{
|
||||
if ( (flag & C352_FLG_LINK) && (flag & C352_FLG_LOOP) )
|
||||
{
|
||||
m_c352_ch[ch].bank = m_c352_ch[ch].start_addr & 0xFF;
|
||||
m_c352_ch[ch].start_addr = m_c352_ch[ch].repeat_addr;
|
||||
m_c352_ch[ch].start = m_c352_ch[ch].start_addr;
|
||||
m_c352_ch[ch].repeat = m_c352_ch[ch].repeat_addr;
|
||||
pos = (m_c352_ch[ch].bank<<16) + m_c352_ch[ch].start_addr;
|
||||
m_c352_ch[ch].flag |= C352_FLG_LOOPHIST;
|
||||
}
|
||||
else if (flag & C352_FLG_LOOP)
|
||||
{
|
||||
pos = (pos & 0xFF0000) + m_c352_ch[ch].repeat;
|
||||
m_c352_ch[ch].flag |= C352_FLG_LOOPHIST;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_c352_ch[ch].flag |= C352_FLG_KEYOFF;
|
||||
m_c352_ch[ch].flag &= ~C352_FLG_BUSY;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pos += cnt;
|
||||
if (
|
||||
(((pos&0xFFFF) > m_c352_ch[ch].end_addr) && ((pos&0xFFFF) < m_c352_ch[ch].start) && (m_c352_ch[ch].start > m_c352_ch[ch].end_addr) ) ||
|
||||
(((pos&0xFFFF) > m_c352_ch[ch].end_addr) && ((pos&0xFFFF) > m_c352_ch[ch].start) && (m_c352_ch[ch].start < m_c352_ch[ch].end_addr) ) ||
|
||||
((pos > (bank|0xFFFF)) && (m_c352_ch[ch].end_addr == 0xFFFF))
|
||||
)
|
||||
{
|
||||
if ( (flag & C352_FLG_LINK) && (flag & C352_FLG_LOOP) )
|
||||
{
|
||||
m_c352_ch[ch].bank = m_c352_ch[ch].start_addr & 0xFF;
|
||||
m_c352_ch[ch].start_addr = m_c352_ch[ch].repeat_addr;
|
||||
m_c352_ch[ch].start = m_c352_ch[ch].start_addr;
|
||||
m_c352_ch[ch].repeat = m_c352_ch[ch].repeat_addr;
|
||||
pos = (m_c352_ch[ch].bank<<16) + m_c352_ch[ch].start_addr;
|
||||
m_c352_ch[ch].flag |= C352_FLG_LOOPHIST;
|
||||
}
|
||||
else if (flag & C352_FLG_LOOP)
|
||||
{
|
||||
pos = (pos & 0xFF0000) + m_c352_ch[ch].repeat;
|
||||
m_c352_ch[ch].flag |= C352_FLG_LOOPHIST;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_c352_ch[ch].flag |= C352_FLG_KEYOFF;
|
||||
m_c352_ch[ch].flag &= ~C352_FLG_BUSY;
|
||||
return;
|
||||
}
|
||||
}
|
||||
v->pos += (v->flags&C352_FLG_REVERSE) ? -1 : 1;
|
||||
}
|
||||
}
|
||||
|
||||
m_c352_ch[ch].noisecnt = noisecnt;
|
||||
m_c352_ch[ch].noisebuf = noisebuf;
|
||||
m_c352_ch[ch].pos = offset;
|
||||
m_c352_ch[ch].current_addr = pos;
|
||||
}
|
||||
|
||||
|
||||
void c352_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
|
||||
{
|
||||
int i, j;
|
||||
stream_sample_t *bufferl = outputs[0];
|
||||
stream_sample_t *bufferr = outputs[1];
|
||||
stream_sample_t *bufferl2 = outputs[2];
|
||||
stream_sample_t *bufferr2 = outputs[3];
|
||||
|
||||
for(i = 0 ; i < samples ; i++)
|
||||
|
||||
int i,j;
|
||||
short s;
|
||||
stream_sample_t *buffer_fl = outputs[0];
|
||||
stream_sample_t *buffer_fr = outputs[1];
|
||||
stream_sample_t *buffer_rl = outputs[2];
|
||||
stream_sample_t *buffer_rr = outputs[3];
|
||||
c352_voice_t* v;
|
||||
|
||||
long out[4];
|
||||
|
||||
for(i=0;i<samples;i++)
|
||||
{
|
||||
m_channel_l[i] = m_channel_r[i] = m_channel_l2[i] = m_channel_r2[i] = 0;
|
||||
}
|
||||
out[0]=out[1]=out[2]=out[3]=0;
|
||||
|
||||
for(j=0;j<32;j++)
|
||||
{
|
||||
|
||||
v = &m_c352_v[j];
|
||||
s = 0;
|
||||
|
||||
if(v->flags & C352_FLG_BUSY)
|
||||
{
|
||||
v->counter += v->freq;
|
||||
|
||||
for (j = 0 ; j < 32 ; j++)
|
||||
{
|
||||
mix_one_channel(j, samples);
|
||||
}
|
||||
if(v->counter > 0x10000)
|
||||
{
|
||||
v->counter &= 0xffff;
|
||||
fetch_sample(v);
|
||||
}
|
||||
|
||||
for(i = 0 ; i < samples ; i++)
|
||||
{
|
||||
*bufferl++ = (short) (m_channel_l[i] >>3);
|
||||
*bufferr++ = (short) (m_channel_r[i] >>3);
|
||||
*bufferl2++ = (short) (m_channel_l2[i] >>3);
|
||||
*bufferr2++ = (short) (m_channel_r2[i] >>3);
|
||||
s = v->sample;
|
||||
|
||||
// Interpolate samples
|
||||
if((v->flags & C352_FLG_FILTER) == 0)
|
||||
s = v->last_sample + (v->counter*(v->sample-v->last_sample)>>16);
|
||||
}
|
||||
|
||||
// Left
|
||||
out[0] += ((v->flags & C352_FLG_PHASEFL) ? -s * (v->vol_f>>8) : s * (v->vol_f>>8))>>8;
|
||||
out[2] += ((v->flags & C352_FLG_PHASERL) ? -s * (v->vol_r>>8) : s * (v->vol_r>>8))>>8;
|
||||
|
||||
// Right
|
||||
out[1] += ((v->flags & C352_FLG_PHASEFR) ? -s * (v->vol_f&0xff) : s * (v->vol_f&0xff))>>8;
|
||||
out[3] += ((v->flags & C352_FLG_PHASEFR) ? -s * (v->vol_r&0xff) : s * (v->vol_r&0xff))>>8;
|
||||
}
|
||||
|
||||
*buffer_fl++ = (short) (out[0]>>3);
|
||||
*buffer_fr++ = (short) (out[1]>>3);
|
||||
*buffer_rl++ = (short) (out[2]>>3);
|
||||
*buffer_rr++ = (short) (out[3]>>3);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
unsigned short c352_device::read_reg16(unsigned long address)
|
||||
{
|
||||
unsigned long chan;
|
||||
unsigned short val;
|
||||
|
||||
m_stream->update();
|
||||
|
||||
chan = (address >> 4) & 0xfff;
|
||||
if (chan > 31)
|
||||
|
||||
const int reg_map[8] =
|
||||
{
|
||||
val = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((address & 0xf) == 6)
|
||||
{
|
||||
val = m_c352_ch[chan].flag;
|
||||
}
|
||||
else
|
||||
{
|
||||
val = 0;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
offsetof(c352_voice_t,vol_f) / sizeof(unsigned short),
|
||||
offsetof(c352_voice_t,vol_r) / sizeof(unsigned short),
|
||||
offsetof(c352_voice_t,freq) / sizeof(unsigned short),
|
||||
offsetof(c352_voice_t,flags) / sizeof(unsigned short),
|
||||
offsetof(c352_voice_t,wave_bank) / sizeof(unsigned short),
|
||||
offsetof(c352_voice_t,wave_start) / sizeof(unsigned short),
|
||||
offsetof(c352_voice_t,wave_end) / sizeof(unsigned short),
|
||||
offsetof(c352_voice_t,wave_loop) / sizeof(unsigned short),
|
||||
};
|
||||
|
||||
if(address < 0x100)
|
||||
return *((unsigned short*)&m_c352_v[address/8]+reg_map[address%8]);
|
||||
else
|
||||
return 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void c352_device::write_reg16(unsigned long address, unsigned short val)
|
||||
{
|
||||
unsigned long chan;
|
||||
int i;
|
||||
|
||||
{
|
||||
m_stream->update();
|
||||
|
||||
chan = (address >> 4) & 0xfff;
|
||||
|
||||
if ( address >= 0x400 )
|
||||
|
||||
const int reg_map[8] =
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
case 0x404: // execute key-ons/offs
|
||||
for ( i = 0 ; i <= 31 ; i++ )
|
||||
{
|
||||
if ( m_c352_ch[i].flag & C352_FLG_KEYON )
|
||||
{
|
||||
if (m_c352_ch[i].start_addr != m_c352_ch[i].end_addr)
|
||||
{
|
||||
m_c352_ch[i].current_addr = (m_c352_ch[i].bank << 16) + m_c352_ch[i].start_addr;
|
||||
m_c352_ch[i].start = m_c352_ch[i].start_addr;
|
||||
m_c352_ch[i].repeat = m_c352_ch[i].repeat_addr;
|
||||
m_c352_ch[i].noisebuf = 0;
|
||||
m_c352_ch[i].noisecnt = 0;
|
||||
m_c352_ch[i].flag &= ~(C352_FLG_KEYON | C352_FLG_LOOPHIST);
|
||||
m_c352_ch[i].flag |= C352_FLG_BUSY;
|
||||
}
|
||||
}
|
||||
else if ( m_c352_ch[i].flag & C352_FLG_KEYOFF )
|
||||
{
|
||||
m_c352_ch[i].flag &= ~C352_FLG_BUSY;
|
||||
m_c352_ch[i].flag &= ~(C352_FLG_KEYOFF);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
offsetof(c352_voice_t,vol_f) / sizeof(unsigned short),
|
||||
offsetof(c352_voice_t,vol_r) / sizeof(unsigned short),
|
||||
offsetof(c352_voice_t,freq) / sizeof(unsigned short),
|
||||
offsetof(c352_voice_t,flags) / sizeof(unsigned short),
|
||||
offsetof(c352_voice_t,wave_bank) / sizeof(unsigned short),
|
||||
offsetof(c352_voice_t,wave_start) / sizeof(unsigned short),
|
||||
offsetof(c352_voice_t,wave_end) / sizeof(unsigned short),
|
||||
offsetof(c352_voice_t,wave_loop) / sizeof(unsigned short),
|
||||
};
|
||||
|
||||
if (chan > 31)
|
||||
int i;
|
||||
|
||||
if(address < 0x100)
|
||||
{
|
||||
LOG(("C352 CTRL %08lx %04x\n", address, val));
|
||||
return;
|
||||
//printf("w %04lx,%04x, %d\n", address, val, reg_map[address&7]);
|
||||
*((unsigned short*)&m_c352_v[address/8]+reg_map[address%8]) = val;
|
||||
}
|
||||
switch(address & 0xf)
|
||||
{
|
||||
case 0x0:
|
||||
// volumes (output 1)
|
||||
LOG(("CH %02ld LVOL %02x RVOL %02x\n", chan, val & 0xff, val >> 8));
|
||||
m_c352_ch[chan].vol_l = val & 0xff;
|
||||
m_c352_ch[chan].vol_r = val >> 8;
|
||||
break;
|
||||
else if(address == 0x200)
|
||||
m_control = val;
|
||||
else if(address == 0x202) // execute keyons/keyoffs
|
||||
{
|
||||
for(i=0;i<32;i++)
|
||||
{
|
||||
if((m_c352_v[i].flags & C352_FLG_KEYON))
|
||||
{
|
||||
m_c352_v[i].pos = (m_c352_v[i].wave_bank<<16) | m_c352_v[i].wave_start;
|
||||
|
||||
case 0x2:
|
||||
// volumes (output 2)
|
||||
LOG(("CH %02ld RLVOL %02x RRVOL %02x\n", chan, val & 0xff, val >> 8));
|
||||
m_c352_ch[chan].vol_l2 = val & 0xff;
|
||||
m_c352_ch[chan].vol_r2 = val >> 8;
|
||||
break;
|
||||
m_c352_v[i].sample = 0;
|
||||
m_c352_v[i].last_sample = 0;
|
||||
m_c352_v[i].counter = 0x10000;
|
||||
|
||||
case 0x4:
|
||||
// pitch
|
||||
LOG(("CH %02ld PITCH %04x\n", chan, val));
|
||||
m_c352_ch[chan].pitch = val;
|
||||
break;
|
||||
|
||||
case 0x6:
|
||||
// flags
|
||||
LOG(("CH %02ld FLAG %02x\n", chan, val));
|
||||
m_c352_ch[chan].flag = val;
|
||||
break;
|
||||
|
||||
case 0x8:
|
||||
// bank (bits 16-31 of address);
|
||||
m_c352_ch[chan].bank = val & 0xff;
|
||||
LOG(("CH %02ld BANK %02x", chan, m_c352_ch[chan].bank));
|
||||
break;
|
||||
|
||||
case 0xa:
|
||||
// start address
|
||||
LOG(("CH %02ld SADDR %04x\n", chan, val));
|
||||
m_c352_ch[chan].start_addr = val;
|
||||
break;
|
||||
|
||||
case 0xc:
|
||||
// end address
|
||||
LOG(("CH %02ld EADDR %04x\n", chan, val));
|
||||
m_c352_ch[chan].end_addr = val;
|
||||
break;
|
||||
|
||||
case 0xe:
|
||||
// loop address
|
||||
LOG(("CH %02ld LADDR %04x\n", chan, val));
|
||||
m_c352_ch[chan].repeat_addr = val;
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG(("CH %02ld UNKN %01lx %04x", chan, address & 0xf, val));
|
||||
break;
|
||||
}
|
||||
m_c352_v[i].flags |= C352_FLG_BUSY;
|
||||
m_c352_v[i].flags &= ~(C352_FLG_KEYON|C352_FLG_LOOPHIST);
|
||||
|
||||
//printf("voice %d : pos= %08x\n",i,m_c352_v[i].pos);
|
||||
}
|
||||
else if(m_c352_v[i].flags & C352_FLG_KEYOFF)
|
||||
{
|
||||
m_c352_v[i].flags &= ~(C352_FLG_BUSY|C352_FLG_KEYOFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void c352_device::device_start()
|
||||
@ -486,45 +269,44 @@ void c352_device::device_start()
|
||||
// register save state info
|
||||
for (i = 0; i < 32; i++)
|
||||
{
|
||||
save_item(NAME(m_c352_ch[i].vol_l), i);
|
||||
save_item(NAME(m_c352_ch[i].vol_r), i);
|
||||
save_item(NAME(m_c352_ch[i].vol_l2), i);
|
||||
save_item(NAME(m_c352_ch[i].vol_r2), i);
|
||||
save_item(NAME(m_c352_ch[i].bank), i);
|
||||
save_item(NAME(m_c352_ch[i].noise), i);
|
||||
save_item(NAME(m_c352_ch[i].noisebuf), i);
|
||||
save_item(NAME(m_c352_ch[i].noisecnt), i);
|
||||
save_item(NAME(m_c352_ch[i].pitch), i);
|
||||
save_item(NAME(m_c352_ch[i].start_addr), i);
|
||||
save_item(NAME(m_c352_ch[i].end_addr), i);
|
||||
save_item(NAME(m_c352_ch[i].repeat_addr), i);
|
||||
save_item(NAME(m_c352_ch[i].flag), i);
|
||||
save_item(NAME(m_c352_ch[i].start), i);
|
||||
save_item(NAME(m_c352_ch[i].repeat), i);
|
||||
save_item(NAME(m_c352_ch[i].current_addr), i);
|
||||
save_item(NAME(m_c352_ch[i].pos), i);
|
||||
save_item(NAME(m_c352_v[i].pos), i);
|
||||
save_item(NAME(m_c352_v[i].counter), i);
|
||||
save_item(NAME(m_c352_v[i].sample), i);
|
||||
save_item(NAME(m_c352_v[i].last_sample), i);
|
||||
save_item(NAME(m_c352_v[i].vol_f), i);
|
||||
save_item(NAME(m_c352_v[i].vol_r), i);
|
||||
save_item(NAME(m_c352_v[i].freq), i);
|
||||
save_item(NAME(m_c352_v[i].flags), i);
|
||||
save_item(NAME(m_c352_v[i].wave_bank), i);
|
||||
save_item(NAME(m_c352_v[i].wave_start), i);
|
||||
save_item(NAME(m_c352_v[i].wave_end), i);
|
||||
save_item(NAME(m_c352_v[i].wave_loop), i);
|
||||
}
|
||||
save_item(NAME(m_random));
|
||||
save_item(NAME(m_control));
|
||||
|
||||
}
|
||||
|
||||
void c352_device::device_reset()
|
||||
{
|
||||
// clear all channels states
|
||||
memset(m_c352_ch, 0, sizeof(c352_ch_t)*32);
|
||||
memset(m_c352_v, 0, sizeof(c352_voice_t)*32);
|
||||
|
||||
// init noise generator
|
||||
m_mseq_reg = 0x12345678;
|
||||
m_random = 0x1234;
|
||||
m_control = 0;
|
||||
}
|
||||
|
||||
READ16_MEMBER( c352_device::read )
|
||||
{
|
||||
return(read_reg16(offset*2));
|
||||
return(read_reg16(offset));
|
||||
}
|
||||
|
||||
WRITE16_MEMBER( c352_device::write )
|
||||
{
|
||||
if (mem_mask == 0xffff)
|
||||
{
|
||||
write_reg16(offset*2, data);
|
||||
write_reg16(offset, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1,5 +1,5 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:R. Belmont
|
||||
// copyright-holders:R. Belmont, superctr
|
||||
#pragma once
|
||||
|
||||
#ifndef __C352_H__
|
||||
@ -66,44 +66,38 @@ private:
|
||||
C352_FLG_LOOP = 0x0002, // loop forward
|
||||
C352_FLG_REVERSE = 0x0001 // play sample backwards
|
||||
};
|
||||
|
||||
struct c352_voice_t {
|
||||
|
||||
struct c352_ch_t
|
||||
{
|
||||
UINT8 vol_l;
|
||||
UINT8 vol_r;
|
||||
UINT8 vol_l2;
|
||||
UINT8 vol_r2;
|
||||
UINT8 bank;
|
||||
INT16 noise;
|
||||
INT16 noisebuf;
|
||||
UINT16 noisecnt;
|
||||
UINT16 pitch;
|
||||
UINT16 start_addr;
|
||||
UINT16 end_addr;
|
||||
UINT16 repeat_addr;
|
||||
UINT32 flag;
|
||||
unsigned int pos;
|
||||
unsigned int counter;
|
||||
|
||||
short sample;
|
||||
short last_sample;
|
||||
|
||||
unsigned short vol_f;
|
||||
unsigned short vol_r;
|
||||
unsigned short freq;
|
||||
unsigned short flags;
|
||||
|
||||
unsigned short wave_bank;
|
||||
unsigned short wave_start;
|
||||
unsigned short wave_end;
|
||||
unsigned short wave_loop;
|
||||
|
||||
UINT16 start;
|
||||
UINT16 repeat;
|
||||
UINT32 current_addr;
|
||||
UINT32 pos;
|
||||
};
|
||||
|
||||
c352_ch_t m_c352_ch[32];
|
||||
|
||||
int m_sample_rate_base;
|
||||
int m_divider;
|
||||
|
||||
long m_channel_l[2048*2];
|
||||
long m_channel_r[2048*2];
|
||||
long m_channel_l2[2048*2];
|
||||
long m_channel_r2[2048*2];
|
||||
|
||||
|
||||
c352_voice_t m_c352_v[32];
|
||||
short m_mulaw_table[256];
|
||||
unsigned int m_mseq_reg;
|
||||
|
||||
unsigned short m_random;
|
||||
unsigned short m_control; // control flags, purpose unknown.
|
||||
|
||||
void fetch_sample(c352_voice_t* v);
|
||||
|
||||
// private functions
|
||||
int get_mseq_bit(void);
|
||||
void mix_one_channel(unsigned long ch, long sample_count);
|
||||
unsigned short read_reg16(unsigned long address);
|
||||
void write_reg16(unsigned long address, unsigned short val);
|
||||
};
|
||||
|
@ -611,10 +611,10 @@ static MACHINE_CONFIG_START( namcofl, namcofl_state )
|
||||
|
||||
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
|
||||
MCFG_C352_ADD("c352", 48384000/2, 288)
|
||||
MCFG_SOUND_ROUTE(0, "rspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(1, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(2, "rspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(3, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(0, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(1, "rspeaker", 1.00)
|
||||
//MCFG_SOUND_ROUTE(2, "lspeaker", 1.00) // Second DAC not present.
|
||||
//MCFG_SOUND_ROUTE(3, "rspeaker", 1.00)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
ROM_START( speedrcr )
|
||||
|
@ -1146,10 +1146,10 @@ static MACHINE_CONFIG_START( namconb1, namconb1_state )
|
||||
|
||||
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
|
||||
MCFG_C352_ADD("c352", MASTER_CLOCK/2, 288)
|
||||
MCFG_SOUND_ROUTE(0, "rspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(1, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(2, "rspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(3, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(0, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(1, "rspeaker", 1.00)
|
||||
//MCFG_SOUND_ROUTE(2, "lspeaker", 1.00) // Second DAC not present.
|
||||
//MCFG_SOUND_ROUTE(3, "rspeaker", 1.00)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
static MACHINE_CONFIG_START( namconb2, namconb1_state )
|
||||
|
@ -209,10 +209,10 @@ static MACHINE_CONFIG_START( namcond1, namcond1_state )
|
||||
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
|
||||
|
||||
MCFG_C352_ADD("c352", XTAL_49_152MHz/2, 288)
|
||||
MCFG_SOUND_ROUTE(0, "rspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(1, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(2, "rspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(3, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(0, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(1, "rspeaker", 1.00)
|
||||
//MCFG_SOUND_ROUTE(2, "lspeaker", 1.00) // Second DAC not present.
|
||||
//MCFG_SOUND_ROUTE(3, "rspeaker", 1.00)
|
||||
|
||||
MCFG_AT28C16_ADD( "at28c16", nullptr )
|
||||
|
||||
|
@ -593,11 +593,11 @@ static MACHINE_CONFIG_START( coh110, namcos11_state )
|
||||
|
||||
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
|
||||
|
||||
MCFG_C352_ADD("c352", 20013200, 228)
|
||||
MCFG_SOUND_ROUTE(0, "rspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(1, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(2, "rspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(3, "lspeaker", 1.00)
|
||||
MCFG_C352_ADD("c352", 25401600, 288)
|
||||
MCFG_SOUND_ROUTE(0, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(1, "rspeaker", 1.00)
|
||||
//MCFG_SOUND_ROUTE(2, "lspeaker", 1.00) // Second DAC not present.
|
||||
//MCFG_SOUND_ROUTE(3, "rspeaker", 1.00)
|
||||
|
||||
MCFG_AT28C16_ADD( "at28c16", nullptr )
|
||||
MACHINE_CONFIG_END
|
||||
|
@ -1665,7 +1665,7 @@ static MACHINE_CONFIG_START( coh700, namcos12_state )
|
||||
|
||||
MCFG_PSX_DMA_CHANNEL_READ( "maincpu", 5, psx_dma_read_delegate( FUNC( namcos12_state::namcos12_rom_read ), (namcos12_state *) owner ) )
|
||||
|
||||
MCFG_CPU_ADD("sub", H83002, 16737350)
|
||||
MCFG_CPU_ADD("sub", H83002, 16934400) // frequency based on research (superctr)
|
||||
MCFG_CPU_PROGRAM_MAP(s12h8rwmap)
|
||||
MCFG_CPU_IO_MAP(s12h8iomap)
|
||||
|
||||
@ -1691,11 +1691,11 @@ static MACHINE_CONFIG_START( coh700, namcos12_state )
|
||||
/* sound hardware */
|
||||
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
|
||||
|
||||
MCFG_C352_ADD("c352", 29168000, 332)
|
||||
MCFG_SOUND_ROUTE(0, "rspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(1, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(2, "rspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(3, "lspeaker", 1.00)
|
||||
MCFG_C352_ADD("c352", 25401600, 288)
|
||||
MCFG_SOUND_ROUTE(0, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(1, "rspeaker", 1.00)
|
||||
//MCFG_SOUND_ROUTE(2, "lspeaker", 1.00) // Second DAC not present.
|
||||
//MCFG_SOUND_ROUTE(3, "rspeaker", 1.00)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
static MACHINE_CONFIG_DERIVED( ptblank2, coh700 )
|
||||
|
@ -3781,10 +3781,10 @@ static MACHINE_CONFIG_START( namcos22, namcos22_state )
|
||||
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
|
||||
|
||||
MCFG_C352_ADD("c352", SS22_MASTER_CLOCK/2, 288)
|
||||
MCFG_SOUND_ROUTE(0, "rspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(1, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(2, "rspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(3, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(0, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(1, "rspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(2, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(3, "rspeaker", 1.00)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
|
||||
@ -3840,10 +3840,10 @@ static MACHINE_CONFIG_START( namcos22s, namcos22_state )
|
||||
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
|
||||
|
||||
MCFG_C352_ADD("c352", SS22_MASTER_CLOCK/2, 288)
|
||||
MCFG_SOUND_ROUTE(0, "rspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(1, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(2, "rspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(3, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(0, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(1, "rspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(2, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(3, "rspeaker", 1.00)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
static MACHINE_CONFIG_DERIVED( alpine, namcos22s )
|
||||
|
@ -1267,10 +1267,17 @@ Notes:
|
||||
#include "machine/namco_settings.h"
|
||||
|
||||
#define JVSCLOCK (XTAL_14_7456MHz)
|
||||
#define H8CLOCK (16737350) /* from 2061 */
|
||||
#define BUSCLOCK (16737350*2) /* 33MHz CPU bus clock / input */
|
||||
#define C352CLOCK (25992000) /* measured at 25.992MHz from 2061 pin 9 */
|
||||
#define C352DIV (296)
|
||||
|
||||
//#define H8CLOCK (16737350) /* from 2061 */
|
||||
//#define BUSCLOCK (16737350*2) /* 33MHz CPU bus clock / input */
|
||||
//#define C352CLOCK (25401600) /* previously measured at 25.992MHz from 2061 pin 9 */
|
||||
//#define C352DIV (296)
|
||||
|
||||
#define H8CLOCK (16934400) /* based on research (superctr) */
|
||||
#define BUSCLOCK (16934400*2)
|
||||
#define C352CLOCK (25401600)
|
||||
#define C352DIV (288)
|
||||
|
||||
#define VSYNC1 (59.8824)
|
||||
#define VSYNC2 (59.915)
|
||||
#define HSYNC (16666150)
|
||||
@ -3587,10 +3594,10 @@ static MACHINE_CONFIG_START( gorgon, namcos23_state )
|
||||
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
|
||||
|
||||
MCFG_C352_ADD("c352", C352CLOCK, C352DIV)
|
||||
MCFG_SOUND_ROUTE(0, "rspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(1, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(2, "rspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(3, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(0, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(1, "rspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(2, "lspeaker", 1.00)
|
||||
MCFG_SOUND_ROUTE(3, "rspeaker", 1.00)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user