C352: implement volume ramping, rewrite mulaw algorithm

- implement volume ramping behavior and confirmed with recording of
  real hardware (Tekken 3)
- rewrote mulaw algorithm. This is not quite perfect yet but is closer
  to recordings and sounds a bit clearer (example: Time Crisis)
This commit is contained in:
superctr 2017-02-10 00:52:25 +01:00
parent 1184004e2c
commit bbce1673c0
2 changed files with 47 additions and 38 deletions

View File

@ -72,14 +72,18 @@ void c352_device::fetch_sample(c352_voice_t* v)
} }
else else
{ {
int8_t s; int8_t s, s2;
s = (int8_t)read_byte(v->pos); s = (int8_t)read_byte(v->pos);
v->sample = s<<8;
if(v->flags & C352_FLG_MULAW) if(v->flags & C352_FLG_MULAW)
v->sample = m_mulaw_table[(uint8_t)s]; {
else s2 = (s&0x7f)>>4;
v->sample = s<<8;
v->sample = ((s2*s2)<<4) - (~(s2<<1)) * (s&0x0f);
v->sample = (s&0x80) ? (~v->sample)<<5 : v->sample<<5;
}
uint16_t pos = v->pos&0xffff; uint16_t pos = v->pos&0xffff;
@ -120,11 +124,18 @@ void c352_device::fetch_sample(c352_voice_t* v)
} }
} }
void c352_device::ramp_volume(c352_voice_t* v,int ch,uint8_t val)
{
int16_t vol_delta = v->curr_vol[ch] - val;
if(vol_delta != 0)
v->curr_vol[ch] += (vol_delta>0) ? -1 : 1;
}
void c352_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) void c352_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{ {
int i,j; int i,j;
int16_t s; int16_t s;
int32_t next_counter;
stream_sample_t *buffer_fl = outputs[0]; stream_sample_t *buffer_fl = outputs[0];
stream_sample_t *buffer_fr = outputs[1]; stream_sample_t *buffer_fr = outputs[1];
stream_sample_t *buffer_rl = outputs[2]; stream_sample_t *buffer_rl = outputs[2];
@ -145,13 +156,22 @@ void c352_device::sound_stream_update(sound_stream &stream, stream_sample_t **in
if(v->flags & C352_FLG_BUSY) if(v->flags & C352_FLG_BUSY)
{ {
v->counter += v->freq; next_counter = v->counter+v->freq;
if(v->counter > 0x10000) if(next_counter & 0x10000)
{ {
v->counter &= 0xffff;
fetch_sample(v); fetch_sample(v);
} }
if((next_counter^v->counter) & 0x18000)
{
ramp_volume(v,0,v->vol_f>>8);
ramp_volume(v,1,v->vol_f&0xff);
ramp_volume(v,2,v->vol_r>>8);
ramp_volume(v,3,v->vol_r&0xff);
}
v->counter = next_counter&0xffff;
s = v->sample; s = v->sample;
@ -161,12 +181,12 @@ void c352_device::sound_stream_update(sound_stream &stream, stream_sample_t **in
} }
// Left // Left
out[0] += ((v->flags & C352_FLG_PHASEFL) ? -s * (v->vol_f>>8) : s * (v->vol_f>>8))>>8; out[0] += (((v->flags & C352_FLG_PHASEFL) ? -s : s) * v->curr_vol[0])>>8;
out[2] += ((v->flags & C352_FLG_PHASERL) ? -s * (v->vol_r>>8) : s * (v->vol_r>>8))>>8; out[2] += (((v->flags & C352_FLG_PHASEFR) ? -s : s) * v->curr_vol[2])>>8;
// Right // Right
out[1] += ((v->flags & C352_FLG_PHASEFR) ? -s * (v->vol_f&0xff) : s * (v->vol_f&0xff))>>8; out[1] += (((v->flags & C352_FLG_PHASERL) ? -s : s) * v->curr_vol[1])>>8;
out[3] += ((v->flags & C352_FLG_PHASEFR) ? -s * (v->vol_r&0xff) : s * (v->vol_r&0xff))>>8; out[3] += (((v->flags & C352_FLG_PHASERL) ? -s : s) * v->curr_vol[3])>>8;
} }
*buffer_fl++ = (int16_t) (out[0]>>3); *buffer_fl++ = (int16_t) (out[0]>>3);
@ -174,8 +194,6 @@ void c352_device::sound_stream_update(sound_stream &stream, stream_sample_t **in
*buffer_rl++ = (int16_t) (out[2]>>3); *buffer_rl++ = (int16_t) (out[2]>>3);
*buffer_rr++ = (int16_t) (out[3]>>3); *buffer_rr++ = (int16_t) (out[3]>>3);
} }
} }
uint16_t c352_device::read_reg16(unsigned long address) uint16_t c352_device::read_reg16(unsigned long address)
@ -196,6 +214,8 @@ uint16_t c352_device::read_reg16(unsigned long address)
if(address < 0x100) if(address < 0x100)
return *((uint16_t*)&m_c352_v[address/8]+reg_map[address%8]); return *((uint16_t*)&m_c352_v[address/8]+reg_map[address%8]);
else if(address == 0x200)
return m_control;
else else
return 0; return 0;
@ -222,11 +242,13 @@ void c352_device::write_reg16(unsigned long address, unsigned short val)
if(address < 0x100) if(address < 0x100)
{ {
//printf("w %04lx,%04x, %d\n", address, val, reg_map[address&7]);
*((uint16_t*)&m_c352_v[address/8]+reg_map[address%8]) = val; *((uint16_t*)&m_c352_v[address/8]+reg_map[address%8]) = val;
} }
else if(address == 0x200) else if(address == 0x200)
{
m_control = val; m_control = val;
logerror("C352 control register write: %04x\n",val);
}
else if(address == 0x202) // execute keyons/keyoffs else if(address == 0x202) // execute keyons/keyoffs
{ {
for(i=0;i<32;i++) for(i=0;i<32;i++)
@ -237,16 +259,18 @@ void c352_device::write_reg16(unsigned long address, unsigned short val)
m_c352_v[i].sample = 0; m_c352_v[i].sample = 0;
m_c352_v[i].last_sample = 0; m_c352_v[i].last_sample = 0;
m_c352_v[i].counter = 0x10000; m_c352_v[i].counter = 0xffff;
m_c352_v[i].flags |= C352_FLG_BUSY; m_c352_v[i].flags |= C352_FLG_BUSY;
m_c352_v[i].flags &= ~(C352_FLG_KEYON|C352_FLG_LOOPHIST); m_c352_v[i].flags &= ~(C352_FLG_KEYON|C352_FLG_LOOPHIST);
//printf("voice %d : pos= %08x\n",i,m_c352_v[i].pos); m_c352_v[i].curr_vol[0] = m_c352_v[i].curr_vol[1] = 0;
m_c352_v[i].curr_vol[2] = m_c352_v[i].curr_vol[3] = 0;
} }
else if(m_c352_v[i].flags & C352_FLG_KEYOFF) else if(m_c352_v[i].flags & C352_FLG_KEYOFF)
{ {
m_c352_v[i].flags &= ~(C352_FLG_BUSY|C352_FLG_KEYOFF); m_c352_v[i].flags &= ~(C352_FLG_BUSY|C352_FLG_KEYOFF);
m_c352_v[i].counter = 0xffff;
} }
} }
} }
@ -264,27 +288,11 @@ void c352_device::device_clock_changed()
void c352_device::device_start() void c352_device::device_start()
{ {
int i; int i;
double x_max = 32752.0;
double y_max = 127.0;
double u = 10.0;
m_sample_rate_base = clock() / m_divider; m_sample_rate_base = clock() / m_divider;
m_stream = machine().sound().stream_alloc(*this, 0, 4, m_sample_rate_base); m_stream = machine().sound().stream_alloc(*this, 0, 4, m_sample_rate_base);
// generate mulaw table for mulaw format samples
for (i = 0; i < 256; i++)
{
double y = (double) (i & 0x7f);
double x = (exp (y / y_max * log (1.0 + u)) - 1.0) * x_max / u;
if (i & 0x80)
{
x = -x;
}
m_mulaw_table[i] = (uint16_t)x;
}
// register save state info // register save state info
for (i = 0; i < 32; i++) for (i = 0; i < 32; i++)
{ {
@ -294,6 +302,7 @@ void c352_device::device_start()
save_item(NAME(m_c352_v[i].last_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_f), i);
save_item(NAME(m_c352_v[i].vol_r), i); save_item(NAME(m_c352_v[i].vol_r), i);
save_item(NAME(m_c352_v[i].curr_vol), i);
save_item(NAME(m_c352_v[i].freq), 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].flags), i);
save_item(NAME(m_c352_v[i].wave_bank), i); save_item(NAME(m_c352_v[i].wave_bank), i);
@ -303,7 +312,6 @@ void c352_device::device_start()
} }
save_item(NAME(m_random)); save_item(NAME(m_random));
save_item(NAME(m_control)); save_item(NAME(m_control));
} }
void c352_device::device_reset() void c352_device::device_reset()
@ -325,7 +333,6 @@ WRITE16_MEMBER( c352_device::write )
{ {
if (mem_mask == 0xffff) if (mem_mask == 0xffff)
{ {
//printf("%04x: %04x\n", offset, data);
write_reg16(offset, data); write_reg16(offset, data);
} }
else else

View File

@ -81,6 +81,8 @@ private:
uint16_t vol_f; uint16_t vol_f;
uint16_t vol_r; uint16_t vol_r;
uint8_t curr_vol[4];
uint16_t freq; uint16_t freq;
uint16_t flags; uint16_t flags;
@ -95,12 +97,12 @@ private:
int m_divider; int m_divider;
c352_voice_t m_c352_v[32]; c352_voice_t m_c352_v[32];
int16_t m_mulaw_table[256];
uint16_t m_random; uint16_t m_random;
uint16_t m_control; // control flags, purpose unknown. uint16_t m_control; // control flags, purpose unknown.
void fetch_sample(c352_voice_t* v); void fetch_sample(c352_voice_t* v);
void ramp_volume(c352_voice_t* v,int ch,uint8_t val);
unsigned short read_reg16(unsigned long address); unsigned short read_reg16(unsigned long address);
void write_reg16(unsigned long address, unsigned short val); void write_reg16(unsigned long address, unsigned short val);