es5506.cpp : Correct algorithms, Allow signed shifting (#5837)

* es5506.cpp : Correct algorithms, Allow signed shifting

* es5506.cpp : Fix envelope
This commit is contained in:
cam900 2019-11-01 12:22:26 +09:00 committed by R. Belmont
parent a9d7e55ac2
commit f9d0e395ba
2 changed files with 135 additions and 134 deletions

View File

@ -284,7 +284,7 @@ void es5506_device::device_start()
} }
/* compute the tables */ /* compute the tables */
compute_tables(VOLUME_BIT_ES5506, 4, 8, 11); // 4 bit exponent, 8 bit mantissa compute_tables(VOLUME_BIT_ES5506, 4, 8); // 4 bit exponent, 8 bit mantissa
/* initialize the rest of the structure */ /* initialize the rest of the structure */
m_channels = channels; m_channels = channels;
@ -301,8 +301,8 @@ void es5506_device::device_start()
{ {
m_voice[j].index = j; m_voice[j].index = j;
m_voice[j].control = CONTROL_STOPMASK; m_voice[j].control = CONTROL_STOPMASK;
m_voice[j].lvol = 0xffff << m_volume_shift; // 16 bit volume m_voice[j].lvol = get_shifted_volume(0xffff); // 16 bit volume
m_voice[j].rvol = 0xffff << m_volume_shift; m_voice[j].rvol = get_shifted_volume(0xffff);
m_voice[j].exbank = 0; m_voice[j].exbank = 0;
} }
@ -404,7 +404,7 @@ void es5505_device::device_start()
} }
/* compute the tables */ /* compute the tables */
compute_tables(VOLUME_BIT_ES5505, 4, 4, 15); // 4 bit exponent, 4 bit mantissa compute_tables(VOLUME_BIT_ES5505, 4, 4); // 4 bit exponent, 4 bit mantissa
/* initialize the rest of the structure */ /* initialize the rest of the structure */
m_channels = channels; m_channels = channels;
@ -416,8 +416,8 @@ void es5505_device::device_start()
{ {
m_voice[j].index = j; m_voice[j].index = j;
m_voice[j].control = CONTROL_STOPMASK; m_voice[j].control = CONTROL_STOPMASK;
m_voice[j].lvol = 0xff << m_volume_shift; // 8 bit volume m_voice[j].lvol = get_shifted_volume(0xff); // 8 bit volume
m_voice[j].rvol = 0xff << m_volume_shift; m_voice[j].rvol = get_shifted_volume(0xff);
m_voice[j].exbank = 0; m_voice[j].exbank = 0;
} }
@ -462,7 +462,7 @@ void es550x_device::update_internal_irq_state()
***********************************************************************************************/ ***********************************************************************************************/
void es550x_device::compute_tables(u32 total_volume_bit, u32 exponent_bit, u32 mantissa_bit, u32 mantissa_shift) void es550x_device::compute_tables(u32 total_volume_bit, u32 exponent_bit, u32 mantissa_bit)
{ {
/* allocate ulaw lookup table */ /* allocate ulaw lookup table */
m_ulaw_lookup = make_unique_clear<s16[]>(1 << ULAW_MAXBITS); m_ulaw_lookup = make_unique_clear<s16[]>(1 << ULAW_MAXBITS);
@ -491,16 +491,21 @@ void es550x_device::compute_tables(u32 total_volume_bit, u32 exponent_bit, u32 m
m_volume_lookup = make_unique_clear<u32[]>(volume_len); m_volume_lookup = make_unique_clear<u32[]>(volume_len);
/* generate volume lookup table */ /* generate volume lookup table */
const u8 exponent_mask = (1 << exponent_bit) - 1; const u32 exponent_shift = 1 << exponent_bit;
const u32 exponent_mask = exponent_shift - 1;
const u32 mantissa_len = (1 << mantissa_bit); const u32 mantissa_len = (1 << mantissa_bit);
const u32 mantissa_mask = (mantissa_len - 1); const u32 mantissa_mask = (mantissa_len - 1);
const u32 mantissa_shift = exponent_shift - mantissa_bit - 1;
for (int i = 0; i < volume_len; i++) for (int i = 0; i < volume_len; i++)
{ {
const u8 exponent = (i >> mantissa_bit) & exponent_mask; const u32 exponent = (i >> mantissa_bit) & exponent_mask;
const u32 mantissa = (i & mantissa_mask) | mantissa_len; const u32 mantissa = (i & mantissa_mask) | mantissa_len;
m_volume_lookup[i] = (mantissa << mantissa_shift) >> ((mantissa_shift + mantissa_bit + 1) - exponent); m_volume_lookup[i] = (mantissa << mantissa_shift) >> (exponent_shift - exponent);
} }
m_volume_acc_shift = (16 + exponent_mask) - VOLUME_ACC_BIT;
} }
/********************************************************************************************** /**********************************************************************************************
@ -511,8 +516,10 @@ void es550x_device::compute_tables(u32 total_volume_bit, u32 exponent_bit, u32 m
void es550x_device::get_accum_mask(u32 address_integer, u32 address_frac) void es550x_device::get_accum_mask(u32 address_integer, u32 address_frac)
{ {
m_accum_shift = ADDRESS_FRAC_BIT - address_frac; m_address_acc_shift = ADDRESS_FRAC_BIT - address_frac;
m_accum_mask = (((((1 << address_integer) - 1) << address_frac) | ((1 << address_frac) - 1)) << m_accum_shift) | ((1 << m_accum_shift) - 1); m_address_acc_mask = lshift_signed<u64, s8>(((((1 << address_integer) - 1) << address_frac) | ((1 << address_frac) - 1)), m_address_acc_shift);
if (m_address_acc_shift > 0)
m_address_acc_mask |= ((1 << m_address_acc_shift) - 1);
} }
@ -522,11 +529,11 @@ void es550x_device::get_accum_mask(u32 address_integer, u32 address_frac)
***********************************************************************************************/ ***********************************************************************************************/
inline s32 es550x_device::interpolate(s32 sample1, s32 sample2, u32 accum) inline s32 es550x_device::interpolate(s32 sample1, s32 sample2, u64 accum)
{ {
const u32 shifted = 1 << ADDRESS_FRAC_BIT; const u32 shifted = 1 << ADDRESS_FRAC_BIT;
const u32 mask = shifted - 1; const u32 mask = shifted - 1;
accum &= mask & m_accum_mask; accum &= mask & m_address_acc_mask;
return (sample1 * (s32)(shifted - accum) + return (sample1 * (s32)(shifted - accum) +
sample2 * (s32)(accum)) >> ADDRESS_FRAC_BIT; sample2 * (s32)(accum)) >> ADDRESS_FRAC_BIT;
} }
@ -625,23 +632,28 @@ inline void es550x_device::apply_filters(es550x_voice *voice, s32 &sample)
inline void es5506_device::update_envelopes(es550x_voice *voice) inline void es5506_device::update_envelopes(es550x_voice *voice)
{ {
const u32 volume_max = (1 << VOLUME_BIT_ES5506) - 1;
/* decrement the envelope counter */ /* decrement the envelope counter */
voice->ecount--; voice->ecount--;
/* ramp left volume */ /* ramp left volume */
if (voice->lvramp) if (voice->lvramp)
{ {
voice->lvol = get_shifted_volume_res(voice->lvol);
voice->lvol += (int8_t)voice->lvramp; voice->lvol += (int8_t)voice->lvramp;
if ((s32)voice->lvol < 0) voice->lvol = 0; if ((s32)voice->lvol < 0) voice->lvol = 0;
else if (voice->lvol > 0xffff) voice->lvol = 0xffff; else if (voice->lvol > volume_max) voice->lvol = volume_max;
voice->lvol = get_shifted_volume(voice->lvol);
} }
/* ramp right volume */ /* ramp right volume */
if (voice->rvramp) if (voice->rvramp)
{ {
voice->rvol = get_shifted_volume_res(voice->rvol);
voice->rvol += (int8_t)voice->rvramp; voice->rvol += (int8_t)voice->rvramp;
if ((s32)voice->rvol < 0) voice->rvol = 0; if ((s32)voice->rvol < 0) voice->rvol = 0;
else if (voice->rvol > 0xffff) voice->rvol = 0xffff; else if (voice->rvol > volume_max) voice->rvol = volume_max;
voice->rvol = get_shifted_volume(voice->rvol);
} }
/* ramp k1 filter constant */ /* ramp k1 filter constant */
@ -679,7 +691,7 @@ inline void es5505_device::update_envelopes(es550x_voice *voice)
***********************************************************************************************/ ***********************************************************************************************/
inline void es5506_device::check_for_end_forward(es550x_voice *voice, u32 &accum) inline void es5506_device::check_for_end_forward(es550x_voice *voice, u64 &accum)
{ {
/* are we past the end? */ /* are we past the end? */
if (accum > voice->end && !(voice->control & CONTROL_LEI)) if (accum > voice->end && !(voice->control & CONTROL_LEI))
@ -698,25 +710,25 @@ inline void es5506_device::check_for_end_forward(es550x_voice *voice, u32 &accum
/* uni-directional looping */ /* uni-directional looping */
case CONTROL_LPE: case CONTROL_LPE:
accum = (voice->start + (accum - voice->end)) & m_accum_mask; accum = (voice->start + (accum - voice->end)) & m_address_acc_mask;
break; break;
/* trans-wave looping */ /* trans-wave looping */
case CONTROL_BLE: case CONTROL_BLE:
accum = (voice->start + (accum - voice->end)) & m_accum_mask; accum = (voice->start + (accum - voice->end)) & m_address_acc_mask;
voice->control = (voice->control & ~CONTROL_LOOPMASK) | CONTROL_LEI; voice->control = (voice->control & ~CONTROL_LOOPMASK) | CONTROL_LEI;
break; break;
/* bi-directional looping */ /* bi-directional looping */
case CONTROL_LPE | CONTROL_BLE: case CONTROL_LPE | CONTROL_BLE:
accum = (voice->end - (accum - voice->end)) & m_accum_mask; accum = (voice->end - (accum - voice->end)) & m_address_acc_mask;
voice->control ^= CONTROL_DIR; voice->control ^= CONTROL_DIR;
break; break;
} }
} }
} }
inline void es5506_device::check_for_end_reverse(es550x_voice *voice, u32 &accum) inline void es5506_device::check_for_end_reverse(es550x_voice *voice, u64 &accum)
{ {
/* are we past the end? */ /* are we past the end? */
if (accum < voice->start && !(voice->control & CONTROL_LEI)) if (accum < voice->start && !(voice->control & CONTROL_LEI))
@ -735,18 +747,18 @@ inline void es5506_device::check_for_end_reverse(es550x_voice *voice, u32 &accum
/* uni-directional looping */ /* uni-directional looping */
case CONTROL_LPE: case CONTROL_LPE:
accum = (voice->end - (voice->start - accum)) & m_accum_mask; accum = (voice->end - (voice->start - accum)) & m_address_acc_mask;
break; break;
/* trans-wave looping */ /* trans-wave looping */
case CONTROL_BLE: case CONTROL_BLE:
accum = (voice->end - (voice->start - accum)) & m_accum_mask; accum = (voice->end - (voice->start - accum)) & m_address_acc_mask;
voice->control = (voice->control & ~CONTROL_LOOPMASK) | CONTROL_LEI; voice->control = (voice->control & ~CONTROL_LOOPMASK) | CONTROL_LEI;
break; break;
/* bi-directional looping */ /* bi-directional looping */
case CONTROL_LPE | CONTROL_BLE: case CONTROL_LPE | CONTROL_BLE:
accum = (voice->start + (voice->start - accum)) & m_accum_mask; accum = (voice->start + (voice->start - accum)) & m_address_acc_mask;
voice->control ^= CONTROL_DIR; voice->control ^= CONTROL_DIR;
break; break;
} }
@ -754,7 +766,7 @@ inline void es5506_device::check_for_end_reverse(es550x_voice *voice, u32 &accum
} }
// ES5505 : BLE is ignored when LPE = 0 // ES5505 : BLE is ignored when LPE = 0
inline void es5505_device::check_for_end_forward(es550x_voice *voice, u32 &accum) inline void es5505_device::check_for_end_forward(es550x_voice *voice, u64 &accum)
{ {
/* are we past the end? */ /* are we past the end? */
if (accum > voice->end) if (accum > voice->end)
@ -774,19 +786,19 @@ inline void es5505_device::check_for_end_forward(es550x_voice *voice, u32 &accum
/* uni-directional looping */ /* uni-directional looping */
case CONTROL_LPE: case CONTROL_LPE:
accum = (voice->start + (accum - voice->end)) & m_accum_mask; accum = (voice->start + (accum - voice->end)) & m_address_acc_mask;
break; break;
/* bi-directional looping */ /* bi-directional looping */
case CONTROL_LPE | CONTROL_BLE: case CONTROL_LPE | CONTROL_BLE:
accum = (voice->end - (accum - voice->end)) & m_accum_mask; accum = (voice->end - (accum - voice->end)) & m_address_acc_mask;
voice->control ^= CONTROL_DIR; voice->control ^= CONTROL_DIR;
break; break;
} }
} }
} }
inline void es5505_device::check_for_end_reverse(es550x_voice *voice, u32 &accum) inline void es5505_device::check_for_end_reverse(es550x_voice *voice, u64 &accum)
{ {
/* are we past the end? */ /* are we past the end? */
if (accum < voice->start) if (accum < voice->start)
@ -806,12 +818,12 @@ inline void es5505_device::check_for_end_reverse(es550x_voice *voice, u32 &accum
/* uni-directional looping */ /* uni-directional looping */
case CONTROL_LPE: case CONTROL_LPE:
accum = (voice->end - (voice->start - accum)) & m_accum_mask; accum = (voice->end - (voice->start - accum)) & m_address_acc_mask;
break; break;
/* bi-directional looping */ /* bi-directional looping */
case CONTROL_LPE | CONTROL_BLE: case CONTROL_LPE | CONTROL_BLE:
accum = (voice->start + (voice->start - accum)) & m_accum_mask; accum = (voice->start + (voice->start - accum)) & m_address_acc_mask;
voice->control ^= CONTROL_DIR; voice->control ^= CONTROL_DIR;
break; break;
} }
@ -829,7 +841,7 @@ inline void es5505_device::check_for_end_reverse(es550x_voice *voice, u32 &accum
void es550x_device::generate_dummy(es550x_voice *voice, u16 *base, s32 *lbuffer, s32 *rbuffer, int samples) void es550x_device::generate_dummy(es550x_voice *voice, u16 *base, s32 *lbuffer, s32 *rbuffer, int samples)
{ {
const u32 freqcount = voice->freqcount; const u32 freqcount = voice->freqcount;
u32 accum = voice->accum & m_accum_mask; u64 accum = voice->accum & m_address_acc_mask;
/* outer loop, in case we switch directions */ /* outer loop, in case we switch directions */
if (!(voice->control & CONTROL_STOPMASK)) if (!(voice->control & CONTROL_STOPMASK))
@ -838,7 +850,7 @@ void es550x_device::generate_dummy(es550x_voice *voice, u16 *base, s32 *lbuffer,
if (!(voice->control & CONTROL_DIR)) if (!(voice->control & CONTROL_DIR))
{ {
/* fetch two samples */ /* fetch two samples */
accum = (accum + freqcount) & m_accum_mask; accum = (accum + freqcount) & m_address_acc_mask;
/* update filters/volumes */ /* update filters/volumes */
if (voice->ecount != 0) if (voice->ecount != 0)
@ -852,7 +864,7 @@ void es550x_device::generate_dummy(es550x_voice *voice, u16 *base, s32 *lbuffer,
else else
{ {
/* fetch two samples */ /* fetch two samples */
accum = (accum - freqcount) & m_accum_mask; accum = (accum - freqcount) & m_address_acc_mask;
/* update filters/volumes */ /* update filters/volumes */
if (voice->ecount != 0) if (voice->ecount != 0)
@ -882,9 +894,7 @@ void es550x_device::generate_dummy(es550x_voice *voice, u16 *base, s32 *lbuffer,
void es550x_device::generate_ulaw(es550x_voice *voice, u16 *base, s32 *lbuffer, s32 *rbuffer, int samples) void es550x_device::generate_ulaw(es550x_voice *voice, u16 *base, s32 *lbuffer, s32 *rbuffer, int samples)
{ {
const u32 freqcount = voice->freqcount; const u32 freqcount = voice->freqcount;
u32 accum = voice->accum & m_accum_mask; u64 accum = voice->accum & m_address_acc_mask;
s32 lvol = get_volume(voice->lvol);
s32 rvol = get_volume(voice->rvol);
/* pre-add the bank offset */ /* pre-add the bank offset */
base += voice->exbank; base += voice->exbank;
@ -905,22 +915,18 @@ void es550x_device::generate_ulaw(es550x_voice *voice, u16 *base, s32 *lbuffer,
/* interpolate */ /* interpolate */
val1 = interpolate(val1, val2, accum); val1 = interpolate(val1, val2, accum);
accum = (accum + freqcount) & m_accum_mask; accum = (accum + freqcount) & m_address_acc_mask;
/* apply filters */ /* apply filters */
apply_filters(voice, val1); apply_filters(voice, val1);
/* update filters/volumes */ /* update filters/volumes */
if (voice->ecount != 0) if (voice->ecount != 0)
{
update_envelopes(voice); update_envelopes(voice);
lvol = get_volume(voice->lvol);
rvol = get_volume(voice->rvol);
}
/* apply volumes and add */ /* apply volumes and add */
*lbuffer += (val1 * lvol) >> VOLUME_ACC_SHIFT; *lbuffer += get_sample(val1, voice->lvol);
*rbuffer += (val1 * rvol) >> VOLUME_ACC_SHIFT; *rbuffer += get_sample(val1, voice->rvol);
/* check for loop end */ /* check for loop end */
check_for_end_forward(voice, accum); check_for_end_forward(voice, accum);
@ -939,22 +945,18 @@ void es550x_device::generate_ulaw(es550x_voice *voice, u16 *base, s32 *lbuffer,
/* interpolate */ /* interpolate */
val1 = interpolate(val1, val2, accum); val1 = interpolate(val1, val2, accum);
accum = (accum - freqcount) & m_accum_mask; accum = (accum - freqcount) & m_address_acc_mask;
/* apply filters */ /* apply filters */
apply_filters(voice, val1); apply_filters(voice, val1);
/* update filters/volumes */ /* update filters/volumes */
if (voice->ecount != 0) if (voice->ecount != 0)
{
update_envelopes(voice); update_envelopes(voice);
lvol = get_volume(voice->lvol);
rvol = get_volume(voice->rvol);
}
/* apply volumes and add */ /* apply volumes and add */
*lbuffer += (val1 * lvol) >> VOLUME_ACC_SHIFT; *lbuffer += get_sample(val1, voice->lvol);
*rbuffer += (val1 * rvol) >> VOLUME_ACC_SHIFT; *rbuffer += get_sample(val1, voice->rvol);
/* check for loop end */ /* check for loop end */
check_for_end_reverse(voice, accum); check_for_end_reverse(voice, accum);
@ -981,9 +983,7 @@ void es550x_device::generate_ulaw(es550x_voice *voice, u16 *base, s32 *lbuffer,
void es550x_device::generate_pcm(es550x_voice *voice, u16 *base, s32 *lbuffer, s32 *rbuffer, int samples) void es550x_device::generate_pcm(es550x_voice *voice, u16 *base, s32 *lbuffer, s32 *rbuffer, int samples)
{ {
const u32 freqcount = voice->freqcount; const u32 freqcount = voice->freqcount;
u32 accum = voice->accum & m_accum_mask; u64 accum = voice->accum & m_address_acc_mask;
s32 lvol = get_volume(voice->lvol);
s32 rvol = get_volume(voice->rvol);
/* pre-add the bank offset */ /* pre-add the bank offset */
base += voice->exbank; base += voice->exbank;
@ -1000,22 +1000,18 @@ void es550x_device::generate_pcm(es550x_voice *voice, u16 *base, s32 *lbuffer, s
/* interpolate */ /* interpolate */
val1 = interpolate(val1, val2, accum); val1 = interpolate(val1, val2, accum);
accum = (accum + freqcount) & m_accum_mask; accum = (accum + freqcount) & m_address_acc_mask;
/* apply filters */ /* apply filters */
apply_filters(voice, val1); apply_filters(voice, val1);
/* update filters/volumes */ /* update filters/volumes */
if (voice->ecount != 0) if (voice->ecount != 0)
{
update_envelopes(voice); update_envelopes(voice);
lvol = get_volume(voice->lvol);
rvol = get_volume(voice->rvol);
}
/* apply volumes and add */ /* apply volumes and add */
*lbuffer += (val1 * lvol) >> VOLUME_ACC_SHIFT; *lbuffer += get_sample(val1, voice->lvol);
*rbuffer += (val1 * rvol) >> VOLUME_ACC_SHIFT; *rbuffer += get_sample(val1, voice->rvol);
/* check for loop end */ /* check for loop end */
check_for_end_forward(voice, accum); check_for_end_forward(voice, accum);
@ -1030,22 +1026,18 @@ void es550x_device::generate_pcm(es550x_voice *voice, u16 *base, s32 *lbuffer, s
/* interpolate */ /* interpolate */
val1 = interpolate(val1, val2, accum); val1 = interpolate(val1, val2, accum);
accum = (accum - freqcount) & m_accum_mask; accum = (accum - freqcount) & m_address_acc_mask;
/* apply filters */ /* apply filters */
apply_filters(voice, val1); apply_filters(voice, val1);
/* update filters/volumes */ /* update filters/volumes */
if (voice->ecount != 0) if (voice->ecount != 0)
{
update_envelopes(voice); update_envelopes(voice);
lvol = get_volume(voice->lvol);
rvol = get_volume(voice->rvol);
}
/* apply volumes and add */ /* apply volumes and add */
*lbuffer += (val1 * lvol) >> VOLUME_ACC_SHIFT; *lbuffer += get_sample(val1, voice->lvol);
*rbuffer += (val1 * rvol) >> VOLUME_ACC_SHIFT; *rbuffer += get_sample(val1, voice->rvol);
/* check for loop end */ /* check for loop end */
check_for_end_reverse(voice, accum); check_for_end_reverse(voice, accum);
@ -1221,13 +1213,13 @@ inline void es5506_device::reg_write_low(es550x_voice *voice, offs_t offset, u32
break; break;
case 0x08/8: /* FC */ case 0x08/8: /* FC */
voice->freqcount = get_accum_shifted_val(data & 0x1ffff); voice->freqcount = get_address_acc_shifted_val(data & 0x1ffff);
LOG("voice %d, freq count=%08x\n", m_current_page & 0x1f, get_accum_res(voice->freqcount)); LOG("voice %d, freq count=%08x\n", m_current_page & 0x1f, get_address_acc_res(voice->freqcount));
break; break;
case 0x10/8: /* LVOL */ case 0x10/8: /* LVOL */
voice->lvol = data & 0xffff; // low 4 bit is used for finer envelope control voice->lvol = get_shifted_volume(data & 0xffff); // low 4 bit is used for finer envelope control
LOG("voice %d, left vol=%04x\n", m_current_page & 0x1f, voice->lvol); LOG("voice %d, left vol=%04x\n", m_current_page & 0x1f, get_shifted_volume_res(voice->lvol));
break; break;
case 0x18/8: /* LVRAMP */ case 0x18/8: /* LVRAMP */
@ -1236,8 +1228,8 @@ inline void es5506_device::reg_write_low(es550x_voice *voice, offs_t offset, u32
break; break;
case 0x20/8: /* RVOL */ case 0x20/8: /* RVOL */
voice->rvol = data & 0xffff; // low 4 bit is used for finer envelope control voice->rvol = get_shifted_volume(data & 0xffff); // low 4 bit is used for finer envelope control
LOG("voice %d, right vol=%04x\n", m_current_page & 0x1f, voice->rvol); LOG("voice %d, right vol=%04x\n", m_current_page & 0x1f, get_shifted_volume_res(voice->rvol));
break; break;
case 0x28/8: /* RVRAMP */ case 0x28/8: /* RVRAMP */
@ -1311,18 +1303,18 @@ inline void es5506_device::reg_write_high(es550x_voice *voice, offs_t offset, u3
break; break;
case 0x08/8: /* START */ case 0x08/8: /* START */
voice->start = get_accum_shifted_val(data & 0xfffff800); voice->start = get_address_acc_shifted_val(data & 0xfffff800);
LOG("voice %d, loop start=%08x\n", m_current_page & 0x1f, get_accum_res(voice->start)); LOG("voice %d, loop start=%08x\n", m_current_page & 0x1f, get_address_acc_res(voice->start));
break; break;
case 0x10/8: /* END */ case 0x10/8: /* END */
voice->end = get_accum_shifted_val(data & 0xffffff80); voice->end = get_address_acc_shifted_val(data & 0xffffff80);
LOG("voice %d, loop end=%08x\n", m_current_page & 0x1f, get_accum_res(voice->end)); LOG("voice %d, loop end=%08x\n", m_current_page & 0x1f, get_address_acc_res(voice->end));
break; break;
case 0x18/8: /* ACCUM */ case 0x18/8: /* ACCUM */
voice->accum = get_accum_shifted_val(data); voice->accum = get_address_acc_shifted_val(data);
LOG("voice %d, accum=%08x\n", m_current_page & 0x1f, get_accum_res(voice->accum)); LOG("voice %d, accum=%08x\n", m_current_page & 0x1f, get_address_acc_res(voice->accum));
break; break;
case 0x20/8: /* O4(n-1) */ case 0x20/8: /* O4(n-1) */
@ -1489,11 +1481,11 @@ inline u32 es5506_device::reg_read_low(es550x_voice *voice, offs_t offset)
break; break;
case 0x08/8: /* FC */ case 0x08/8: /* FC */
result = get_accum_res(voice->freqcount); result = get_address_acc_res(voice->freqcount);
break; break;
case 0x10/8: /* LVOL */ case 0x10/8: /* LVOL */
result = voice->lvol; result = get_shifted_volume_res(voice->lvol);
break; break;
case 0x18/8: /* LVRAMP */ case 0x18/8: /* LVRAMP */
@ -1501,7 +1493,7 @@ inline u32 es5506_device::reg_read_low(es550x_voice *voice, offs_t offset)
break; break;
case 0x20/8: /* RVOL */ case 0x20/8: /* RVOL */
result = voice->rvol; result = get_shifted_volume_res(voice->rvol);
break; break;
case 0x28/8: /* RVRAMP */ case 0x28/8: /* RVRAMP */
@ -1566,15 +1558,15 @@ inline u32 es5506_device::reg_read_high(es550x_voice *voice, offs_t offset)
break; break;
case 0x08/8: /* START */ case 0x08/8: /* START */
result = get_accum_res(voice->start); result = get_address_acc_res(voice->start);
break; break;
case 0x10/8: /* END */ case 0x10/8: /* END */
result = get_accum_res(voice->end); result = get_address_acc_res(voice->end);
break; break;
case 0x18/8: /* ACCUM */ case 0x18/8: /* ACCUM */
result = get_accum_res(voice->accum); result = get_address_acc_res(voice->accum);
break; break;
case 0x20/8: /* O4(n-1) */ case 0x20/8: /* O4(n-1) */
@ -1717,48 +1709,48 @@ inline void es5505_device::reg_write_low(es550x_voice *voice, offs_t offset, u16
case 0x01: /* FC */ case 0x01: /* FC */
if (ACCESSING_BITS_0_7) if (ACCESSING_BITS_0_7)
voice->freqcount = (voice->freqcount & ~get_accum_shifted_val(0x00fe, 1)) | (get_accum_shifted_val((data & 0x00fe), 1)); voice->freqcount = (voice->freqcount & ~get_address_acc_shifted_val(0x00fe, 1)) | (get_address_acc_shifted_val((data & 0x00fe), 1));
if (ACCESSING_BITS_8_15) if (ACCESSING_BITS_8_15)
voice->freqcount = (voice->freqcount & ~get_accum_shifted_val(0xff00, 1)) | (get_accum_shifted_val((data & 0xff00), 1)); voice->freqcount = (voice->freqcount & ~get_address_acc_shifted_val(0xff00, 1)) | (get_address_acc_shifted_val((data & 0xff00), 1));
LOG("%s:voice %d, freq count=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_accum_res(voice->freqcount, 1)); LOG("%s:voice %d, freq count=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_address_acc_res(voice->freqcount, 1));
break; break;
case 0x02: /* STRT (hi) */ case 0x02: /* STRT (hi) */
if (ACCESSING_BITS_0_7) if (ACCESSING_BITS_0_7)
voice->start = (voice->start & ~get_accum_shifted_val(0x00ff0000)) | (get_accum_shifted_val((data & 0x00ff) << 16)); voice->start = (voice->start & ~get_address_acc_shifted_val(0x00ff0000)) | (get_address_acc_shifted_val((data & 0x00ff) << 16));
if (ACCESSING_BITS_8_15) if (ACCESSING_BITS_8_15)
voice->start = (voice->start & ~get_accum_shifted_val(0x1f000000)) | (get_accum_shifted_val((data & 0x1f00) << 16)); voice->start = (voice->start & ~get_address_acc_shifted_val(0x1f000000)) | (get_address_acc_shifted_val((data & 0x1f00) << 16));
LOG("%s:voice %d, loop start=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_accum_res(voice->start)); LOG("%s:voice %d, loop start=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_address_acc_res(voice->start));
break; break;
case 0x03: /* STRT (lo) */ case 0x03: /* STRT (lo) */
if (ACCESSING_BITS_0_7) if (ACCESSING_BITS_0_7)
voice->start = (voice->start & ~get_accum_shifted_val(0x000000e0)) | (get_accum_shifted_val(data & 0x00e0)); voice->start = (voice->start & ~get_address_acc_shifted_val(0x000000e0)) | (get_address_acc_shifted_val(data & 0x00e0));
if (ACCESSING_BITS_8_15) if (ACCESSING_BITS_8_15)
voice->start = (voice->start & ~get_accum_shifted_val(0x0000ff00)) | (get_accum_shifted_val(data & 0xff00)); voice->start = (voice->start & ~get_address_acc_shifted_val(0x0000ff00)) | (get_address_acc_shifted_val(data & 0xff00));
LOG("%s:voice %d, loop start=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_accum_res(voice->start)); LOG("%s:voice %d, loop start=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_address_acc_res(voice->start));
break; break;
case 0x04: /* END (hi) */ case 0x04: /* END (hi) */
if (ACCESSING_BITS_0_7) if (ACCESSING_BITS_0_7)
voice->end = (voice->end & ~get_accum_shifted_val(0x00ff0000)) | (get_accum_shifted_val((data & 0x00ff) << 16)); voice->end = (voice->end & ~get_address_acc_shifted_val(0x00ff0000)) | (get_address_acc_shifted_val((data & 0x00ff) << 16));
if (ACCESSING_BITS_8_15) if (ACCESSING_BITS_8_15)
voice->end = (voice->end & ~get_accum_shifted_val(0x1f000000)) | (get_accum_shifted_val((data & 0x1f00) << 16)); voice->end = (voice->end & ~get_address_acc_shifted_val(0x1f000000)) | (get_address_acc_shifted_val((data & 0x1f00) << 16));
#if RAINE_CHECK #if RAINE_CHECK
voice->control |= CONTROL_STOP0; voice->control |= CONTROL_STOP0;
#endif #endif
LOG("%s:voice %d, loop end=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_accum_res(voice->end)); LOG("%s:voice %d, loop end=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_address_acc_res(voice->end));
break; break;
case 0x05: /* END (lo) */ case 0x05: /* END (lo) */
if (ACCESSING_BITS_0_7) if (ACCESSING_BITS_0_7)
voice->end = (voice->end & ~get_accum_shifted_val(0x000000e0)) | (get_accum_shifted_val(data & 0x00e0)); voice->end = (voice->end & ~get_address_acc_shifted_val(0x000000e0)) | (get_address_acc_shifted_val(data & 0x00e0));
if (ACCESSING_BITS_8_15) if (ACCESSING_BITS_8_15)
voice->end = (voice->end & ~get_accum_shifted_val(0x0000ff00)) | (get_accum_shifted_val(data & 0xff00)); voice->end = (voice->end & ~get_address_acc_shifted_val(0x0000ff00)) | (get_address_acc_shifted_val(data & 0xff00));
#if RAINE_CHECK #if RAINE_CHECK
voice->control |= CONTROL_STOP0; voice->control |= CONTROL_STOP0;
#endif #endif
LOG("%s:voice %d, loop end=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_accum_res(voice->end)); LOG("%s:voice %d, loop end=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_address_acc_res(voice->end));
break; break;
case 0x06: /* K2 */ case 0x06: /* K2 */
@ -1780,29 +1772,29 @@ inline void es5505_device::reg_write_low(es550x_voice *voice, offs_t offset, u16
case 0x08: /* LVOL */ case 0x08: /* LVOL */
if (ACCESSING_BITS_8_15) if (ACCESSING_BITS_8_15)
voice->lvol = (voice->lvol & ~0xff00) | (data & 0xff00); voice->lvol = (voice->lvol & ~0xff00) | (data & 0xff00);
LOG("%s:voice %d, left vol=%02x\n", machine().describe_context(), m_current_page & 0x1f, voice->lvol >> m_volume_shift); LOG("%s:voice %d, left vol=%02x\n", machine().describe_context(), m_current_page & 0x1f, get_shifted_volume_res(voice->lvol));
break; break;
case 0x09: /* RVOL */ case 0x09: /* RVOL */
if (ACCESSING_BITS_8_15) if (ACCESSING_BITS_8_15)
voice->rvol = (voice->rvol & ~0xff00) | (data & 0xff00); voice->rvol = (voice->rvol & ~0xff00) | (data & 0xff00);
LOG("%s:voice %d, right vol=%02x\n", machine().describe_context(), m_current_page & 0x1f, voice->rvol >> m_volume_shift); LOG("%s:voice %d, right vol=%02x\n", machine().describe_context(), m_current_page & 0x1f, get_shifted_volume_res(voice->rvol));
break; break;
case 0x0a: /* ACC (hi) */ case 0x0a: /* ACC (hi) */
if (ACCESSING_BITS_0_7) if (ACCESSING_BITS_0_7)
voice->accum = (voice->accum & ~get_accum_shifted_val(0x00ff0000)) | (get_accum_shifted_val((data & 0x00ff) << 16)); voice->accum = (voice->accum & ~get_address_acc_shifted_val(0x00ff0000)) | (get_address_acc_shifted_val((data & 0x00ff) << 16));
if (ACCESSING_BITS_8_15) if (ACCESSING_BITS_8_15)
voice->accum = (voice->accum & ~get_accum_shifted_val(0x1f000000)) | (get_accum_shifted_val((data & 0x1f00) << 16)); voice->accum = (voice->accum & ~get_address_acc_shifted_val(0x1f000000)) | (get_address_acc_shifted_val((data & 0x1f00) << 16));
LOG("%s:voice %d, accum=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_accum_res(voice->accum)); LOG("%s:voice %d, accum=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_address_acc_res(voice->accum));
break; break;
case 0x0b: /* ACC (lo) */ case 0x0b: /* ACC (lo) */
if (ACCESSING_BITS_0_7) if (ACCESSING_BITS_0_7)
voice->accum = (voice->accum & ~get_accum_shifted_val(0x000000ff)) | (get_accum_shifted_val(data & 0x00ff)); voice->accum = (voice->accum & ~get_address_acc_shifted_val(0x000000ff)) | (get_address_acc_shifted_val(data & 0x00ff));
if (ACCESSING_BITS_8_15) if (ACCESSING_BITS_8_15)
voice->accum = (voice->accum & ~get_accum_shifted_val(0x0000ff00)) | (get_accum_shifted_val(data & 0xff00)); voice->accum = (voice->accum & ~get_address_acc_shifted_val(0x0000ff00)) | (get_address_acc_shifted_val(data & 0xff00));
LOG("%s:voice %d, accum=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_accum_res(voice->accum)); LOG("%s:voice %d, accum=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_address_acc_res(voice->accum));
break; break;
case 0x0c: /* unused */ case 0x0c: /* unused */
@ -1891,7 +1883,7 @@ inline void es5505_device::reg_write_high(es550x_voice *voice, offs_t offset, u1
voice->o1n1 = (voice->o1n1 & ~0x00ff) | (data & 0x00ff); voice->o1n1 = (voice->o1n1 & ~0x00ff) | (data & 0x00ff);
if (ACCESSING_BITS_8_15) if (ACCESSING_BITS_8_15)
voice->o1n1 = (s16)((voice->o1n1 & ~0xff00) | (data & 0xff00)); voice->o1n1 = (s16)((voice->o1n1 & ~0xff00) | (data & 0xff00));
LOG("%s:voice %d, O1(n-1)=%04x (accum=%08x)\n", machine().describe_context(), m_current_page & 0x1f, voice->o1n1 & 0xffff, get_accum_res(voice->accum)); LOG("%s:voice %d, O1(n-1)=%04x (accum=%08x)\n", machine().describe_context(), m_current_page & 0x1f, voice->o1n1 & 0xffff, get_address_acc_res(voice->accum));
break; break;
case 0x07: case 0x07:
@ -2012,23 +2004,23 @@ inline u16 es5505_device::reg_read_low(es550x_voice *voice, offs_t offset)
break; break;
case 0x01: /* FC */ case 0x01: /* FC */
result = get_accum_res(voice->freqcount, 1); result = get_address_acc_res(voice->freqcount, 1);
break; break;
case 0x02: /* STRT (hi) */ case 0x02: /* STRT (hi) */
result = get_accum_res(voice->start) >> 16; result = get_address_acc_res(voice->start) >> 16;
break; break;
case 0x03: /* STRT (lo) */ case 0x03: /* STRT (lo) */
result = get_accum_res(voice->start); result = get_address_acc_res(voice->start);
break; break;
case 0x04: /* END (hi) */ case 0x04: /* END (hi) */
result = get_accum_res(voice->end) >> 16; result = get_address_acc_res(voice->end) >> 16;
break; break;
case 0x05: /* END (lo) */ case 0x05: /* END (lo) */
result = get_accum_res(voice->end); result = get_address_acc_res(voice->end);
break; break;
case 0x06: /* K2 */ case 0x06: /* K2 */
@ -2048,11 +2040,11 @@ inline u16 es5505_device::reg_read_low(es550x_voice *voice, offs_t offset)
break; break;
case 0x0a: /* ACC (hi) */ case 0x0a: /* ACC (hi) */
result = get_accum_res(voice->accum) >> 16; result = get_address_acc_res(voice->accum) >> 16;
break; break;
case 0x0b: /* ACC (lo) */ case 0x0b: /* ACC (lo) */
result = get_accum_res(voice->accum); result = get_address_acc_res(voice->accum);
break; break;
case 0x0c: /* unused */ case 0x0c: /* unused */

View File

@ -37,7 +37,7 @@ protected:
// constants for volumes // constants for volumes
const u32 FINE_VOLUME_BIT = 16; const u32 FINE_VOLUME_BIT = 16;
const u32 VOLUME_ACC_SHIFT = 11; const u32 VOLUME_ACC_BIT = 20;
// constants for address // constants for address
const u32 ADDRESS_FRAC_BIT = 11; const u32 ADDRESS_FRAC_BIT = 11;
@ -88,23 +88,31 @@ protected:
void update_irq_state(); void update_irq_state();
void update_internal_irq_state(); void update_internal_irq_state();
void compute_tables(u32 total_volume_bit = 16, u32 exponent_bit = 4, u32 mantissa_bit = 8, u32 mantissa_shift = 11); void compute_tables(u32 total_volume_bit = 16, u32 exponent_bit = 4, u32 mantissa_bit = 8);
void get_accum_mask(u32 address_integer, u32 address_frac); void get_accum_mask(u32 address_integer = 21, u32 address_frac = 11);
virtual inline u32 get_bank(u32 control) { return 0; } virtual inline u32 get_bank(u32 control) { return 0; }
virtual inline u32 get_ca(u32 control) { return 0; } virtual inline u32 get_ca(u32 control) { return 0; }
virtual inline u32 get_lp(u32 control) { return 0; } virtual inline u32 get_lp(u32 control) { return 0; }
inline u32 get_volume(u16 volume) { return m_volume_lookup[volume >> m_volume_shift_int]; } template<typename T, typename U> inline T lshift_signed(T val, U shift) { return (shift >= 0) ? val << shift : val >> (-shift); }
inline u32 get_accum_shifted_val(u32 val, int bias = 0) { return val << (m_accum_shift - bias); } template<typename T, typename U> inline T rshift_signed(T val, U shift) { return (shift >= 0) ? val >> shift : val << (-shift); }
inline u32 get_accum_res(u32 val, int bias = 0) { return val >> (m_accum_shift - bias); }
inline u32 get_integer_addr(u32 accum, s32 bias = 0) { return ((accum + (bias << ADDRESS_FRAC_BIT)) & m_accum_mask) >> ADDRESS_FRAC_BIT; }
inline s32 interpolate(s32 sample1, s32 sample2, u32 accum); inline u64 get_shifted_volume_res(u64 volume) { return rshift_signed<u64, s8>(volume, m_volume_shift); }
inline u64 get_shifted_volume(u64 volume) { return lshift_signed<u64, s8>(volume, m_volume_shift); }
inline u64 get_volume(u32 volume) { return m_volume_lookup[rshift_signed<u32, s8>(volume, m_volume_shift_int)]; }
inline u64 get_address_acc_shifted_val(u64 val, int bias = 0) { return lshift_signed<u64, s8>(val, m_address_acc_shift - bias); }
inline u64 get_address_acc_res(u64 val, int bias = 0) { return rshift_signed<u64, s8>(val, m_address_acc_shift - bias); }
inline u64 get_integer_addr(u64 accum, s32 bias = 0) { return ((accum + (bias << ADDRESS_FRAC_BIT)) & m_address_acc_mask) >> ADDRESS_FRAC_BIT; }
inline s64 get_sample(s32 sample, u32 volume) { return rshift_signed<s64, s8>(sample * get_volume(volume), m_volume_acc_shift); }
inline s32 interpolate(s32 sample1, s32 sample2, u64 accum);
inline void apply_filters(es550x_voice *voice, s32 &sample); inline void apply_filters(es550x_voice *voice, s32 &sample);
virtual inline void update_envelopes(es550x_voice *voice) {}; virtual inline void update_envelopes(es550x_voice *voice) {};
virtual inline void check_for_end_forward(es550x_voice *voice, u32 &accum) {}; virtual inline void check_for_end_forward(es550x_voice *voice, u64 &accum) {};
virtual inline void check_for_end_reverse(es550x_voice *voice, u32 &accum) {}; virtual inline void check_for_end_reverse(es550x_voice *voice, u64 &accum) {};
void generate_dummy(es550x_voice *voice, u16 *base, s32 *lbuffer, s32 *rbuffer, int samples); void generate_dummy(es550x_voice *voice, u16 *base, s32 *lbuffer, s32 *rbuffer, int samples);
void generate_ulaw(es550x_voice *voice, u16 *base, s32 *lbuffer, s32 *rbuffer, int samples); void generate_ulaw(es550x_voice *voice, u16 *base, s32 *lbuffer, s32 *rbuffer, int samples);
void generate_pcm(es550x_voice *voice, u16 *base, s32 *lbuffer, s32 *rbuffer, int samples); void generate_pcm(es550x_voice *voice, u16 *base, s32 *lbuffer, s32 *rbuffer, int samples);
@ -116,11 +124,12 @@ protected:
int m_sample_rate; /* current sample rate */ int m_sample_rate; /* current sample rate */
u16 * m_region_base[4]; /* pointer to the base of the region */ u16 * m_region_base[4]; /* pointer to the base of the region */
u32 m_master_clock; /* master clock frequency */ u32 m_master_clock; /* master clock frequency */
u64 m_accum_shift; s8 m_address_acc_shift;
u64 m_accum_mask; u64 m_address_acc_mask;
u64 m_volume_shift; s8 m_volume_shift;
u64 m_volume_shift_int; s8 m_volume_shift_int;
s64 m_volume_acc_shift;
u8 m_current_page; /* current register page */ u8 m_current_page; /* current register page */
u8 m_active_voices; /* number of active voices */ u8 m_active_voices; /* number of active voices */
@ -173,8 +182,8 @@ protected:
virtual inline u32 get_lp(u32 control) override { return (control >> 8) & LP_MASK; } virtual inline u32 get_lp(u32 control) override { return (control >> 8) & LP_MASK; }
virtual inline void update_envelopes(es550x_voice *voice) override; virtual inline void update_envelopes(es550x_voice *voice) override;
virtual inline void check_for_end_forward(es550x_voice *voice, u32 &accum) override; virtual inline void check_for_end_forward(es550x_voice *voice, u64 &accum) override;
virtual inline void check_for_end_reverse(es550x_voice *voice, u32 &accum) override; virtual inline void check_for_end_reverse(es550x_voice *voice, u64 &accum) override;
virtual void generate_samples(s32 **outputs, int offset, int samples) override; virtual void generate_samples(s32 **outputs, int offset, int samples) override;
private: private:
@ -218,8 +227,8 @@ protected:
virtual inline u32 get_bank(u32 control) override { return (control >> 2) & 1; } virtual inline u32 get_bank(u32 control) override { return (control >> 2) & 1; }
virtual inline void update_envelopes(es550x_voice *voice) override; virtual inline void update_envelopes(es550x_voice *voice) override;
virtual inline void check_for_end_forward(es550x_voice *voice, u32 &accum) override; virtual inline void check_for_end_forward(es550x_voice *voice, u64 &accum) override;
virtual inline void check_for_end_reverse(es550x_voice *voice, u32 &accum) override; virtual inline void check_for_end_reverse(es550x_voice *voice, u64 &accum) override;
virtual void generate_samples(s32 **outputs, int offset, int samples) override; virtual void generate_samples(s32 **outputs, int offset, int samples) override;
private: private: