summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound
diff options
context:
space:
mode:
author cam900 <dbtlrchl@naver.com>2019-11-01 12:22:26 +0900
committer R. Belmont <rb6502@users.noreply.github.com>2019-10-31 23:22:26 -0400
commitf9d0e395baf4eae0ba2a13b3739886be57bf959e (patch)
treec65f8c3a9a92c0dea71fcc4c694fbaf20963be82 /src/devices/sound
parenta9d7e55ac21d193db00d416597d999b3da2d9f4f (diff)
es5506.cpp : Correct algorithms, Allow signed shifting (#5837)
* es5506.cpp : Correct algorithms, Allow signed shifting * es5506.cpp : Fix envelope
Diffstat (limited to 'src/devices/sound')
-rw-r--r--src/devices/sound/es5506.cpp224
-rw-r--r--src/devices/sound/es5506.h45
2 files changed, 135 insertions, 134 deletions
diff --git a/src/devices/sound/es5506.cpp b/src/devices/sound/es5506.cpp
index c317435d34f..b7d4d18155f 100644
--- a/src/devices/sound/es5506.cpp
+++ b/src/devices/sound/es5506.cpp
@@ -284,7 +284,7 @@ void es5506_device::device_start()
}
/* 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 */
m_channels = channels;
@@ -301,8 +301,8 @@ void es5506_device::device_start()
{
m_voice[j].index = j;
m_voice[j].control = CONTROL_STOPMASK;
- m_voice[j].lvol = 0xffff << m_volume_shift; // 16 bit volume
- m_voice[j].rvol = 0xffff << m_volume_shift;
+ m_voice[j].lvol = get_shifted_volume(0xffff); // 16 bit volume
+ m_voice[j].rvol = get_shifted_volume(0xffff);
m_voice[j].exbank = 0;
}
@@ -404,7 +404,7 @@ void es5505_device::device_start()
}
/* 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 */
m_channels = channels;
@@ -416,8 +416,8 @@ void es5505_device::device_start()
{
m_voice[j].index = j;
m_voice[j].control = CONTROL_STOPMASK;
- m_voice[j].lvol = 0xff << m_volume_shift; // 8 bit volume
- m_voice[j].rvol = 0xff << m_volume_shift;
+ m_voice[j].lvol = get_shifted_volume(0xff); // 8 bit volume
+ m_voice[j].rvol = get_shifted_volume(0xff);
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 */
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);
/* 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_mask = (mantissa_len - 1);
+ const u32 mantissa_shift = exponent_shift - mantissa_bit - 1;
+
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;
- 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)
{
- m_accum_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_shift = ADDRESS_FRAC_BIT - address_frac;
+ 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 mask = shifted - 1;
- accum &= mask & m_accum_mask;
+ accum &= mask & m_address_acc_mask;
return (sample1 * (s32)(shifted - accum) +
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)
{
+ const u32 volume_max = (1 << VOLUME_BIT_ES5506) - 1;
/* decrement the envelope counter */
voice->ecount--;
/* ramp left volume */
if (voice->lvramp)
{
+ voice->lvol = get_shifted_volume_res(voice->lvol);
voice->lvol += (int8_t)voice->lvramp;
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 */
if (voice->rvramp)
{
+ voice->rvol = get_shifted_volume_res(voice->rvol);
voice->rvol += (int8_t)voice->rvramp;
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 */
@@ -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? */
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 */
case CONTROL_LPE:
- accum = (voice->start + (accum - voice->end)) & m_accum_mask;
+ accum = (voice->start + (accum - voice->end)) & m_address_acc_mask;
break;
/* trans-wave looping */
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;
break;
/* bi-directional looping */
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;
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? */
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 */
case CONTROL_LPE:
- accum = (voice->end - (voice->start - accum)) & m_accum_mask;
+ accum = (voice->end - (voice->start - accum)) & m_address_acc_mask;
break;
/* trans-wave looping */
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;
break;
/* bi-directional looping */
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;
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
-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? */
if (accum > voice->end)
@@ -774,19 +786,19 @@ inline void es5505_device::check_for_end_forward(es550x_voice *voice, u32 &accum
/* uni-directional looping */
case CONTROL_LPE:
- accum = (voice->start + (accum - voice->end)) & m_accum_mask;
+ accum = (voice->start + (accum - voice->end)) & m_address_acc_mask;
break;
/* bi-directional looping */
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;
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? */
if (accum < voice->start)
@@ -806,12 +818,12 @@ inline void es5505_device::check_for_end_reverse(es550x_voice *voice, u32 &accum
/* uni-directional looping */
case CONTROL_LPE:
- accum = (voice->end - (voice->start - accum)) & m_accum_mask;
+ accum = (voice->end - (voice->start - accum)) & m_address_acc_mask;
break;
/* bi-directional looping */
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;
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)
{
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 */
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))
{
/* fetch two samples */
- accum = (accum + freqcount) & m_accum_mask;
+ accum = (accum + freqcount) & m_address_acc_mask;
/* update filters/volumes */
if (voice->ecount != 0)
@@ -852,7 +864,7 @@ void es550x_device::generate_dummy(es550x_voice *voice, u16 *base, s32 *lbuffer,
else
{
/* fetch two samples */
- accum = (accum - freqcount) & m_accum_mask;
+ accum = (accum - freqcount) & m_address_acc_mask;
/* update filters/volumes */
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)
{
const u32 freqcount = voice->freqcount;
- u32 accum = voice->accum & m_accum_mask;
- s32 lvol = get_volume(voice->lvol);
- s32 rvol = get_volume(voice->rvol);
+ u64 accum = voice->accum & m_address_acc_mask;
/* pre-add the bank offset */
base += voice->exbank;
@@ -905,22 +915,18 @@ void es550x_device::generate_ulaw(es550x_voice *voice, u16 *base, s32 *lbuffer,
/* interpolate */
val1 = interpolate(val1, val2, accum);
- accum = (accum + freqcount) & m_accum_mask;
+ accum = (accum + freqcount) & m_address_acc_mask;
/* apply filters */
apply_filters(voice, val1);
/* update filters/volumes */
if (voice->ecount != 0)
- {
update_envelopes(voice);
- lvol = get_volume(voice->lvol);
- rvol = get_volume(voice->rvol);
- }
/* apply volumes and add */
- *lbuffer += (val1 * lvol) >> VOLUME_ACC_SHIFT;
- *rbuffer += (val1 * rvol) >> VOLUME_ACC_SHIFT;
+ *lbuffer += get_sample(val1, voice->lvol);
+ *rbuffer += get_sample(val1, voice->rvol);
/* check for loop end */
check_for_end_forward(voice, accum);
@@ -939,22 +945,18 @@ void es550x_device::generate_ulaw(es550x_voice *voice, u16 *base, s32 *lbuffer,
/* interpolate */
val1 = interpolate(val1, val2, accum);
- accum = (accum - freqcount) & m_accum_mask;
+ accum = (accum - freqcount) & m_address_acc_mask;
/* apply filters */
apply_filters(voice, val1);
/* update filters/volumes */
if (voice->ecount != 0)
- {
update_envelopes(voice);
- lvol = get_volume(voice->lvol);
- rvol = get_volume(voice->rvol);
- }
/* apply volumes and add */
- *lbuffer += (val1 * lvol) >> VOLUME_ACC_SHIFT;
- *rbuffer += (val1 * rvol) >> VOLUME_ACC_SHIFT;
+ *lbuffer += get_sample(val1, voice->lvol);
+ *rbuffer += get_sample(val1, voice->rvol);
/* check for loop end */
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)
{
const u32 freqcount = voice->freqcount;
- u32 accum = voice->accum & m_accum_mask;
- s32 lvol = get_volume(voice->lvol);
- s32 rvol = get_volume(voice->rvol);
+ u64 accum = voice->accum & m_address_acc_mask;
/* pre-add the bank offset */
base += voice->exbank;
@@ -1000,22 +1000,18 @@ void es550x_device::generate_pcm(es550x_voice *voice, u16 *base, s32 *lbuffer, s
/* interpolate */
val1 = interpolate(val1, val2, accum);
- accum = (accum + freqcount) & m_accum_mask;
+ accum = (accum + freqcount) & m_address_acc_mask;
/* apply filters */
apply_filters(voice, val1);
/* update filters/volumes */
if (voice->ecount != 0)
- {
update_envelopes(voice);
- lvol = get_volume(voice->lvol);
- rvol = get_volume(voice->rvol);
- }
/* apply volumes and add */
- *lbuffer += (val1 * lvol) >> VOLUME_ACC_SHIFT;
- *rbuffer += (val1 * rvol) >> VOLUME_ACC_SHIFT;
+ *lbuffer += get_sample(val1, voice->lvol);
+ *rbuffer += get_sample(val1, voice->rvol);
/* check for loop end */
check_for_end_forward(voice, accum);
@@ -1030,22 +1026,18 @@ void es550x_device::generate_pcm(es550x_voice *voice, u16 *base, s32 *lbuffer, s
/* interpolate */
val1 = interpolate(val1, val2, accum);
- accum = (accum - freqcount) & m_accum_mask;
+ accum = (accum - freqcount) & m_address_acc_mask;
/* apply filters */
apply_filters(voice, val1);
/* update filters/volumes */
if (voice->ecount != 0)
- {
update_envelopes(voice);
- lvol = get_volume(voice->lvol);
- rvol = get_volume(voice->rvol);
- }
/* apply volumes and add */
- *lbuffer += (val1 * lvol) >> VOLUME_ACC_SHIFT;
- *rbuffer += (val1 * rvol) >> VOLUME_ACC_SHIFT;
+ *lbuffer += get_sample(val1, voice->lvol);
+ *rbuffer += get_sample(val1, voice->rvol);
/* check for loop end */
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;
case 0x08/8: /* FC */
- voice->freqcount = get_accum_shifted_val(data & 0x1ffff);
- LOG("voice %d, freq count=%08x\n", m_current_page & 0x1f, get_accum_res(voice->freqcount));
+ voice->freqcount = get_address_acc_shifted_val(data & 0x1ffff);
+ LOG("voice %d, freq count=%08x\n", m_current_page & 0x1f, get_address_acc_res(voice->freqcount));
break;
case 0x10/8: /* LVOL */
- voice->lvol = data & 0xffff; // low 4 bit is used for finer envelope control
- LOG("voice %d, left vol=%04x\n", m_current_page & 0x1f, voice->lvol);
+ 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, get_shifted_volume_res(voice->lvol));
break;
case 0x18/8: /* LVRAMP */
@@ -1236,8 +1228,8 @@ inline void es5506_device::reg_write_low(es550x_voice *voice, offs_t offset, u32
break;
case 0x20/8: /* RVOL */
- voice->rvol = data & 0xffff; // low 4 bit is used for finer envelope control
- LOG("voice %d, right vol=%04x\n", m_current_page & 0x1f, voice->rvol);
+ 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, get_shifted_volume_res(voice->rvol));
break;
case 0x28/8: /* RVRAMP */
@@ -1311,18 +1303,18 @@ inline void es5506_device::reg_write_high(es550x_voice *voice, offs_t offset, u3
break;
case 0x08/8: /* START */
- voice->start = get_accum_shifted_val(data & 0xfffff800);
- LOG("voice %d, loop start=%08x\n", m_current_page & 0x1f, get_accum_res(voice->start));
+ voice->start = get_address_acc_shifted_val(data & 0xfffff800);
+ LOG("voice %d, loop start=%08x\n", m_current_page & 0x1f, get_address_acc_res(voice->start));
break;
case 0x10/8: /* END */
- voice->end = get_accum_shifted_val(data & 0xffffff80);
- LOG("voice %d, loop end=%08x\n", m_current_page & 0x1f, get_accum_res(voice->end));
+ voice->end = get_address_acc_shifted_val(data & 0xffffff80);
+ LOG("voice %d, loop end=%08x\n", m_current_page & 0x1f, get_address_acc_res(voice->end));
break;
case 0x18/8: /* ACCUM */
- voice->accum = get_accum_shifted_val(data);
- LOG("voice %d, accum=%08x\n", m_current_page & 0x1f, get_accum_res(voice->accum));
+ voice->accum = get_address_acc_shifted_val(data);
+ LOG("voice %d, accum=%08x\n", m_current_page & 0x1f, get_address_acc_res(voice->accum));
break;
case 0x20/8: /* O4(n-1) */
@@ -1489,11 +1481,11 @@ inline u32 es5506_device::reg_read_low(es550x_voice *voice, offs_t offset)
break;
case 0x08/8: /* FC */
- result = get_accum_res(voice->freqcount);
+ result = get_address_acc_res(voice->freqcount);
break;
case 0x10/8: /* LVOL */
- result = voice->lvol;
+ result = get_shifted_volume_res(voice->lvol);
break;
case 0x18/8: /* LVRAMP */
@@ -1501,7 +1493,7 @@ inline u32 es5506_device::reg_read_low(es550x_voice *voice, offs_t offset)
break;
case 0x20/8: /* RVOL */
- result = voice->rvol;
+ result = get_shifted_volume_res(voice->rvol);
break;
case 0x28/8: /* RVRAMP */
@@ -1566,15 +1558,15 @@ inline u32 es5506_device::reg_read_high(es550x_voice *voice, offs_t offset)
break;
case 0x08/8: /* START */
- result = get_accum_res(voice->start);
+ result = get_address_acc_res(voice->start);
break;
case 0x10/8: /* END */
- result = get_accum_res(voice->end);
+ result = get_address_acc_res(voice->end);
break;
case 0x18/8: /* ACCUM */
- result = get_accum_res(voice->accum);
+ result = get_address_acc_res(voice->accum);
break;
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 */
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)
- voice->freqcount = (voice->freqcount & ~get_accum_shifted_val(0xff00, 1)) | (get_accum_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));
+ 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_address_acc_res(voice->freqcount, 1));
break;
case 0x02: /* STRT (hi) */
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)
- voice->start = (voice->start & ~get_accum_shifted_val(0x1f000000)) | (get_accum_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));
+ 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_address_acc_res(voice->start));
break;
case 0x03: /* STRT (lo) */
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)
- voice->start = (voice->start & ~get_accum_shifted_val(0x0000ff00)) | (get_accum_shifted_val(data & 0xff00));
- LOG("%s:voice %d, loop start=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_accum_res(voice->start));
+ 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_address_acc_res(voice->start));
break;
case 0x04: /* END (hi) */
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)
- 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
voice->control |= CONTROL_STOP0;
#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;
case 0x05: /* END (lo) */
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)
- 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
voice->control |= CONTROL_STOP0;
#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;
case 0x06: /* K2 */
@@ -1780,29 +1772,29 @@ inline void es5505_device::reg_write_low(es550x_voice *voice, offs_t offset, u16
case 0x08: /* LVOL */
if (ACCESSING_BITS_8_15)
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;
case 0x09: /* RVOL */
if (ACCESSING_BITS_8_15)
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;
case 0x0a: /* ACC (hi) */
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)
- voice->accum = (voice->accum & ~get_accum_shifted_val(0x1f000000)) | (get_accum_shifted_val((data & 0x1f00) << 16));
- LOG("%s:voice %d, accum=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_accum_res(voice->accum));
+ 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_address_acc_res(voice->accum));
break;
case 0x0b: /* ACC (lo) */
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)
- voice->accum = (voice->accum & ~get_accum_shifted_val(0x0000ff00)) | (get_accum_shifted_val(data & 0xff00));
- LOG("%s:voice %d, accum=%08x\n", machine().describe_context(), m_current_page & 0x1f, get_accum_res(voice->accum));
+ 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_address_acc_res(voice->accum));
break;
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);
if (ACCESSING_BITS_8_15)
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;
case 0x07:
@@ -2012,23 +2004,23 @@ inline u16 es5505_device::reg_read_low(es550x_voice *voice, offs_t offset)
break;
case 0x01: /* FC */
- result = get_accum_res(voice->freqcount, 1);
+ result = get_address_acc_res(voice->freqcount, 1);
break;
case 0x02: /* STRT (hi) */
- result = get_accum_res(voice->start) >> 16;
+ result = get_address_acc_res(voice->start) >> 16;
break;
case 0x03: /* STRT (lo) */
- result = get_accum_res(voice->start);
+ result = get_address_acc_res(voice->start);
break;
case 0x04: /* END (hi) */
- result = get_accum_res(voice->end) >> 16;
+ result = get_address_acc_res(voice->end) >> 16;
break;
case 0x05: /* END (lo) */
- result = get_accum_res(voice->end);
+ result = get_address_acc_res(voice->end);
break;
case 0x06: /* K2 */
@@ -2048,11 +2040,11 @@ inline u16 es5505_device::reg_read_low(es550x_voice *voice, offs_t offset)
break;
case 0x0a: /* ACC (hi) */
- result = get_accum_res(voice->accum) >> 16;
+ result = get_address_acc_res(voice->accum) >> 16;
break;
case 0x0b: /* ACC (lo) */
- result = get_accum_res(voice->accum);
+ result = get_address_acc_res(voice->accum);
break;
case 0x0c: /* unused */
diff --git a/src/devices/sound/es5506.h b/src/devices/sound/es5506.h
index 0d30537170c..aac2c920912 100644
--- a/src/devices/sound/es5506.h
+++ b/src/devices/sound/es5506.h
@@ -37,7 +37,7 @@ protected:
// constants for volumes
const u32 FINE_VOLUME_BIT = 16;
- const u32 VOLUME_ACC_SHIFT = 11;
+ const u32 VOLUME_ACC_BIT = 20;
// constants for address
const u32 ADDRESS_FRAC_BIT = 11;
@@ -88,23 +88,31 @@ protected:
void update_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 get_accum_mask(u32 address_integer, u32 address_frac);
+ void compute_tables(u32 total_volume_bit = 16, u32 exponent_bit = 4, u32 mantissa_bit = 8);
+ 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_ca(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]; }
- inline u32 get_accum_shifted_val(u32 val, int bias = 0) { return val << (m_accum_shift - bias); }
- 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; }
+ template<typename T, typename U> inline T lshift_signed(T val, U shift) { return (shift >= 0) ? val << shift : val >> (-shift); }
+ template<typename T, typename U> inline T rshift_signed(T val, U shift) { return (shift >= 0) ? val >> shift : val << (-shift); }
- 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);
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_reverse(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, u64 &accum) {};
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_pcm(es550x_voice *voice, u16 *base, s32 *lbuffer, s32 *rbuffer, int samples);
@@ -116,11 +124,12 @@ protected:
int m_sample_rate; /* current sample rate */
u16 * m_region_base[4]; /* pointer to the base of the region */
u32 m_master_clock; /* master clock frequency */
- u64 m_accum_shift;
- u64 m_accum_mask;
+ s8 m_address_acc_shift;
+ u64 m_address_acc_mask;
- u64 m_volume_shift;
- u64 m_volume_shift_int;
+ s8 m_volume_shift;
+ s8 m_volume_shift_int;
+ s64 m_volume_acc_shift;
u8 m_current_page; /* current register page */
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 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_reverse(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, u64 &accum) override;
virtual void generate_samples(s32 **outputs, int offset, int samples) override;
private:
@@ -218,8 +227,8 @@ protected:
virtual inline u32 get_bank(u32 control) override { return (control >> 2) & 1; }
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_reverse(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, u64 &accum) override;
virtual void generate_samples(s32 **outputs, int offset, int samples) override;
private: