mu50: correct default a/d level

swp00: Add more bits to the sample values (24.8 instead of 16.0)
swp00: Cleanups of the meg registers
This commit is contained in:
Olivier Galibert 2023-10-06 22:46:59 +02:00
parent 0c56d5796a
commit 7f9a051492
3 changed files with 103 additions and 67 deletions

View File

@ -123,16 +123,18 @@ bool swp00_device::fpstep(s32 &value, s32 limit, s32 step)
return false;
}
s16 swp00_device::fpapply(s32 value, s16 sample)
// sample is signed 24.8
s32 swp00_device::fpapply(s32 value, s32 sample)
{
if(value >= 0x10000000)
return 0;
return (sample - ((sample * ((value >> 9) & 0x7fff)) >> 16)) >> (value >> 24);
return (s64(sample) - ((s64(sample) * ((value >> 9) & 0x7fff)) >> 16)) >> (value >> 24);
}
s16 swp00_device::lpffpapply(s32 value, s16 sample)
// sample is signed 24.8
s32 swp00_device::lpffpapply(s32 value, s32 sample)
{
return ((((value >> 7) & 0x7fff) | 0x8000) * sample) >> (31 - (value >> 22));
return ((((value >> 7) & 0x7fff) | 0x8000) * s64(sample)) >> (31 - (value >> 22));
}
// Some tables we need. Maybe they're in roms inside the chip,
@ -171,8 +173,10 @@ void swp00_device::device_start()
save_item(NAME(m_waverom_access));
save_item(NAME(m_waverom_val));
save_item(NAME(m_intreg));
save_item(NAME(m_fpreg));
save_item(NAME(m_meg_control));
save_item(NAME(m_off));
save_item(NAME(m_fp));
save_item(NAME(m_lpf_info));
save_item(NAME(m_lpf_speed));
save_item(NAME(m_lfo_famod_depth));
@ -253,9 +257,10 @@ void swp00_device::device_reset()
{
m_waverom_access = 0;
m_waverom_val = 0;
m_meg_control = 0;
std::fill(m_intreg.begin(), m_intreg.end(), 0);
std::fill(m_fpreg.begin(), m_fpreg.end(), 0);
std::fill(m_off.begin(), m_off.end(), 0);
std::fill(m_fp.begin(), m_fp.end(), 0);
std::fill(m_lpf_info.begin(), m_lpf_info.end(), 0);
std::fill(m_lpf_speed.begin(), m_lpf_speed.end(), 0);
std::fill(m_lfo_famod_depth.begin(), m_lfo_famod_depth.end(), 0);
@ -308,8 +313,16 @@ void swp00_device::map(address_map &map)
{
map(0x000, 0x7ff).rw(FUNC(swp00_device::snd_r), FUNC(swp00_device::snd_w));
// 00-01: control
rchan(map, 0x08).w(FUNC(swp00_device::slot8_w)); // always 80
rchan(map, 0x09).w(FUNC(swp00_device::slot9_w)); // always 00
rchan(map, 0x0a).rw(FUNC(swp00_device::sample_start_r<1>), FUNC(swp00_device::sample_start_w<1>));
rchan(map, 0x0b).rw(FUNC(swp00_device::sample_start_r<0>), FUNC(swp00_device::sample_start_w<0>));
// 0c-0f: meg offsets
// 10-1b: meg values
rchan(map, 0x20).rw(FUNC(swp00_device::lpf_info_r<1>), FUNC(swp00_device::lpf_info_w<1>));
rchan(map, 0x21).rw(FUNC(swp00_device::lpf_info_r<0>), FUNC(swp00_device::lpf_info_w<0>));
rchan(map, 0x22).rw(FUNC(swp00_device::lpf_speed_r), FUNC(swp00_device::lpf_speed_w));
@ -335,38 +348,39 @@ void swp00_device::map(address_map &map)
rchan(map, 0x36).rw(FUNC(swp00_device::sample_end_r<1>), FUNC(swp00_device::sample_end_w<1>));
rchan(map, 0x37).rw(FUNC(swp00_device::sample_end_r<0>), FUNC(swp00_device::sample_end_w<0>));
rany(map, 0x00, 0x02).rw(FUNC(swp00_device::waverom_access_r), FUNC(swp00_device::waverom_access_w));
rany(map, 0x00, 0x03).r(FUNC(swp00_device::waverom_val_r));
rany(map, 0x00, 0x08).w(FUNC(swp00_device::keyon_w<3>));
rany(map, 0x00, 0x09).w(FUNC(swp00_device::keyon_w<2>));
rany(map, 0x00, 0x0a).w(FUNC(swp00_device::keyon_w<1>));
rany(map, 0x00, 0x0b).w(FUNC(swp00_device::keyon_w<0>));
rctrl(map, 0x00); // 01 at startup
rctrl(map, 0x01).rw(FUNC(swp00_device::state_r), FUNC(swp00_device::state_adr_w));
rctrl(map, 0x02).rw(FUNC(swp00_device::waverom_access_r), FUNC(swp00_device::waverom_access_w));
rctrl(map, 0x03).r(FUNC(swp00_device::waverom_val_r));
rctrl(map, 0x04).rw(FUNC(swp00_device::meg_control_r), FUNC(swp00_device::meg_control_w));
rctrl(map, 0x08).w(FUNC(swp00_device::keyon_w<3>));
rctrl(map, 0x09).w(FUNC(swp00_device::keyon_w<2>));
rctrl(map, 0x0a).w(FUNC(swp00_device::keyon_w<1>));
rctrl(map, 0x0b).w(FUNC(swp00_device::keyon_w<0>));
rctrl(map, 0x0c); // 00 at startup
rctrl(map, 0x0d); // 00 at startup
rctrl(map, 0x0e); // 00 at startup
map(0x001, 0x001).rw(FUNC(swp00_device::state_r), FUNC(swp00_device::state_adr_w));
map(0x180, 0x1ff).rw(FUNC(swp00_device::intreg_r), FUNC(swp00_device::intreg_w));
map(0x200, 0x3ff).rw(FUNC(swp00_device::fpreg_r), FUNC(swp00_device::fpreg_w));
map(0x180, 0x1ff).rw(FUNC(swp00_device::off_r), FUNC(swp00_device::off_w));
map(0x200, 0x37f).rw(FUNC(swp00_device::fp_r), FUNC(swp00_device::fp_w));
}
// Voice control
#if 0
static double exp_mant_to_double(signed int a1)
void swp00_device::slot8_w(offs_t offset, u8 data)
{
signed int v1; // eax@1
a1 >>= 6;
v1 = a1;
if ( a1 < 0 )
v1 = 0;
return (double)((unsigned short)v1 | 0x10000u) / ((double)(1 << (24 - (v1 >> 16))) * 256.0);
if(data == 0x80)
return;
logerror("slot8[%02x] = %02x\n", offset >> 1, data);
}
static double v2f(s32 value)
void swp00_device::slot9_w(offs_t offset, u8 data)
{
return 1.0 - (1.0 - (value & 0xffffff) / 33554432.0) / (1 << (value >> 24));
if(data == 0x00)
return;
logerror("slot9[%02x] = %02x\n", offset >> 1, data);
}
#endif
template<int sel> void swp00_device::lpf_info_w(offs_t offset, u8 data)
{
@ -744,46 +758,46 @@ template<int sel> void swp00_device::keyon_w(u8 data)
keyon(8*sel+i);
}
void swp00_device::intreg_w(offs_t offset, u8 data)
void swp00_device::off_w(offs_t offset, u8 data)
{
m_stream->update();
if(offset & 1)
m_intreg[offset >> 1] = (m_intreg[offset >> 1] & 0xff00) | data;
m_off[offset >> 1] = (m_off[offset >> 1] & 0xff00) | data;
else
m_intreg[offset >> 1] = (m_intreg[offset >> 1] & 0x00ff) | (data << 8);
if(0)
m_off[offset >> 1] = (m_off[offset >> 1] & 0x00ff) | (data << 8);
if(1)
if(offset & 1)
logerror("intreg[%02x] = %04x\n", offset >> 1, m_intreg[offset >> 1]);
logerror("off[%02x] = %04x\n", 3*(offset >> 1), m_off[offset >> 1]);
}
u8 swp00_device::intreg_r(offs_t offset)
u8 swp00_device::off_r(offs_t offset)
{
if(offset & 1)
return m_intreg[offset >> 1];
return m_off[offset >> 1];
else
return m_intreg[offset >> 1] >> 8;
return m_off[offset >> 1] >> 8;
}
void swp00_device::fpreg_w(offs_t offset, u8 data)
void swp00_device::fp_w(offs_t offset, u8 data)
{
m_stream->update();
if(offset & 1)
m_fpreg[offset >> 1] = (m_fpreg[offset >> 1] & 0xff00) | data;
m_fp[offset >> 1] = (m_fp[offset >> 1] & 0xff00) | data;
else
m_fpreg[offset >> 1] = (m_fpreg[offset >> 1] & 0x00ff) | (data << 8);
if(0)
m_fp[offset >> 1] = (m_fp[offset >> 1] & 0x00ff) | (data << 8);
if(1)
if(offset & 1)
logerror("fpreg[%03x] = %04x\n", offset >> 1, m_fpreg[offset >> 1]);
logerror("fp[%02x] = %04x\n", offset >> 1, m_fp[offset >> 1]);
}
u8 swp00_device::fpreg_r(offs_t offset)
u8 swp00_device::fp_r(offs_t offset)
{
if(offset & 1)
return m_fpreg[offset >> 1];
return m_fp[offset >> 1];
else
return m_fpreg[offset >> 1] >> 8;
return m_fp[offset >> 1] >> 8;
}
void swp00_device::waverom_access_w(u8 data)
@ -804,6 +818,17 @@ u8 swp00_device::waverom_val_r()
return val;
}
void swp00_device::meg_control_w(u8 data)
{
m_meg_control = data;
logerror("meg_control %02x (variation %x, %s)\n", m_meg_control >> 6, m_meg_control & 2 ? "mute" : "on");
}
u8 swp00_device::meg_control_r()
{
return m_meg_control;
}
// Counters state access
u8 swp00_device::state_r()
{
@ -873,8 +898,7 @@ u8 swp00_device::snd_r(offs_t offset)
else
#endif
preg = util::string_format("%02x.%02x", chan, slot);
if(offset != 1)
logerror("snd_r [%03x] %-5s, %02x\n", offset, preg, rr[offset]);
logerror("snd_r [%03x] %-5s, %02x\n", offset, preg, rr[offset]);
}
return rr[offset];
}
@ -905,9 +929,6 @@ void swp00_device::snd_w(offs_t offset, u8 data)
#endif
preg = util::string_format("%02x.%02x", chan, slot);
if(offset == 1)
return;
logerror("snd_w [%03x] %-5s, %02x\n", offset, preg, data);
}
@ -990,7 +1011,7 @@ void swp00_device::sound_stream_update(sound_stream &stream, std::vector<read_st
}
s32 mul = m_sample_pos[chan] & 0x7fff;
s16 sample = (val1 * mul + val0 * (0x8000 - mul)) >> 15;
s32 sample = (val1 * mul + val0 * (0x8000 - mul)) >> 7;
s32 lpf_value = m_lpf_value[chan] + ((lfo_fa_phase * (m_lfo_famod_depth[chan] >> 5)) << (m_lfo_step[chan] & 0x40 ? 2 : 1));
@ -1052,6 +1073,14 @@ void swp00_device::sound_stream_update(sound_stream &stream, std::vector<read_st
m_decay[chan] = istep(m_envelope_level[chan], 0, m_global_step[m_attack_speed[chan]] << 1);
}
dry_l >>= 8;
dry_r >>= 8;
rev >>= 8;
cho_l >>= 8;
cho_r >>= 8;
var_l >>= 8;
var_r >>= 8;
outputs[0].put_int(i, dry_l, 32768);
outputs[1].put_int(i, dry_r, 32768);
(void)rev;

View File

@ -41,9 +41,11 @@ private:
static const std::array<u32, 4> lfo_shape_offset_saw;
static const std::array<u32, 4> lfo_shape_offset_tri;
std::array<u16, 0x40> m_intreg;
std::array<u16, 0x300> m_fpreg;
// MEG registers
std::array<u16, 0x40> m_off;
std::array<u16, 0xc0> m_fp;
// AWM registers
std::array<u16, 0x20> m_lpf_info;
std::array<u8, 0x20> m_lpf_speed;
std::array<u8, 0x20> m_lfo_famod_depth;
@ -83,6 +85,7 @@ private:
u16 m_waverom_val;
u8 m_waverom_access;
u8 m_state_adr;
u8 m_meg_control;
// Voice control
@ -127,15 +130,20 @@ private:
void lfo_pmod_depth_w(offs_t offset, u8 data);
u8 lfo_pmod_depth_r(offs_t offset);
void slot8_w(offs_t offset, u8 data);
void slot9_w(offs_t offset, u8 data);
// Internal state access
u8 state_r();
void state_adr_w(u8 data);
// MEG variables
void intreg_w(offs_t offset, u8 data);
u8 intreg_r(offs_t offset);
void fpreg_w(offs_t offset, u8 data);
u8 fpreg_r(offs_t offset);
// MEG
void off_w(offs_t offset, u8 data);
u8 off_r(offs_t offset);
void fp_w(offs_t offset, u8 data);
u8 fp_r(offs_t offset);
void meg_control_w(u8 data);
u8 meg_control_r();
// Control registers
void keyon(int chan);
@ -149,9 +157,8 @@ private:
u8 snd_r(offs_t offset);
void snd_w(offs_t offset, u8 data);
inline auto &rany(address_map &map, int chan, int idx) {
int slot = (chan << 6) | idx;
return map(slot, slot);
inline auto &rctrl(address_map &map, int idx) {
return map(idx, idx);
}
inline auto &rchan(address_map &map, int idx) {
@ -164,8 +171,8 @@ private:
static bool fpstep(s32 &value, s32 limit, s32 step);
static s32 fpadd(s32 value, s32 step);
static s32 fpsub(s32 value, s32 step);
static s16 fpapply(s32 value, s16 sample);
static s16 lpffpapply(s32 value, s16 sample);
static s32 fpapply(s32 value, s32 sample);
static s32 lpffpapply(s32 value, s32 sample);
};
DECLARE_DEVICE_TYPE(SWP00, swp00_device)

View File

@ -116,16 +116,16 @@ void mu50_state::mu50_map(address_map &map)
map(0x400000, 0x4007ff).m(m_swp00, FUNC(swp00_device::map));
}
// Analog input right (not sent to the swp)
// Analog input right (not sent to the swp, mixing is analog)
u16 mu50_state::adc_ar_r()
{
return 0;
return 0x3ff;
}
// Analog input left (not sent to the swp)
// Analog input left (not sent to the swp, mixing is analog)
u16 mu50_state::adc_al_r()
{
return 0;
return 0x3ff;
}
// Put the host switch to pure midi