diff options
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 |
commit | f9d0e395baf4eae0ba2a13b3739886be57bf959e (patch) | |
tree | c65f8c3a9a92c0dea71fcc4c694fbaf20963be82 /src/devices/sound | |
parent | a9d7e55ac21d193db00d416597d999b3da2d9f4f (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.cpp | 224 | ||||
-rw-r--r-- | src/devices/sound/es5506.h | 45 |
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: |