mirror of
https://github.com/holub/mame
synced 2025-07-05 18:08:04 +03:00
swx00: Initial buggy noise
h8: correct division of negative numbers
This commit is contained in:
parent
047f60403e
commit
e3ed66ec77
@ -788,39 +788,31 @@ macro jsr32 %opc %spreg
|
||||
// Conditions:
|
||||
// p = q*d + r
|
||||
// abs(r) < abs(d)
|
||||
// d and r are same sign or r=0
|
||||
// p and r are same sign or r=0
|
||||
// p = +20, d = +3 -> q = 6, r = 2
|
||||
// p = +20, d = -3 -> q = -6, r = -2
|
||||
// p = -20, d = +3 -> q = -7, r = 1
|
||||
// p = +20, d = -3 -> q = -7, r = 1
|
||||
// p = -20, d = +3 -> q = -6, r = -2
|
||||
// p = -20, d = -3 -> q = 7, r = -1
|
||||
int q, r;
|
||||
if(m_TMP2 & 0x80000000) {
|
||||
if(m_TMP1 & 0x80000000) { // - -
|
||||
q = (-m_TMP1) / (-m_TMP2);
|
||||
r = (-m_TMP1) % (-m_TMP2);
|
||||
if(r) {
|
||||
r = r + m_TMP2;
|
||||
q++;
|
||||
}
|
||||
r = -((-m_TMP1) % (-m_TMP2));
|
||||
} else { // + -
|
||||
m_CCR |= F_N;
|
||||
q = -(m_TMP1 / (-m_TMP2));
|
||||
r = -(m_TMP1 % (-m_TMP2));
|
||||
r = m_TMP1 % (-m_TMP2);
|
||||
}
|
||||
} else {
|
||||
if(m_TMP1 & 0x80000000) { // - +
|
||||
m_CCR |= F_N;
|
||||
q = -((-m_TMP1) / m_TMP2);
|
||||
r = (-m_TMP1) % m_TMP2;
|
||||
if(r) {
|
||||
r = m_TMP2 - r;
|
||||
q--;
|
||||
}
|
||||
r = -((-m_TMP1) % m_TMP2);
|
||||
} else { // + +
|
||||
q = m_TMP1 / m_TMP2;
|
||||
r = m_TMP1 % m_TMP2;
|
||||
}
|
||||
}
|
||||
if(q < 0)
|
||||
m_CCR |= F_N;
|
||||
r16_w(m_IR[1], (q & 0xff) | ((r & 0xff) << 8));
|
||||
}
|
||||
prefetch_done();
|
||||
@ -837,39 +829,31 @@ macro jsr32 %opc %spreg
|
||||
// Conditions:
|
||||
// p = q*d + r
|
||||
// abs(r) < abs(d)
|
||||
// d and r are same sign or r=0
|
||||
// p and r are same sign or r=0
|
||||
// p = +20, d = +3 -> q = 6, r = 2
|
||||
// p = +20, d = -3 -> q = -6, r = -2
|
||||
// p = -20, d = +3 -> q = -7, r = 1
|
||||
// p = +20, d = -3 -> q = -7, r = 1
|
||||
// p = -20, d = +3 -> q = -6, r = -2
|
||||
// p = -20, d = -3 -> q = 7, r = -1
|
||||
int q, r;
|
||||
if(m_TMP2 & 0x80000000) {
|
||||
if(m_TMP1 & 0x80000000) { // - -
|
||||
q = (-m_TMP1) / (-m_TMP2);
|
||||
r = (-m_TMP1) % (-m_TMP2);
|
||||
if(r) {
|
||||
r = r + m_TMP2;
|
||||
q++;
|
||||
}
|
||||
r = -((-m_TMP1) % (-m_TMP2));
|
||||
} else { // + -
|
||||
m_CCR |= F_N;
|
||||
q = -(m_TMP1 / (-m_TMP2));
|
||||
r = -(m_TMP1 % (-m_TMP2));
|
||||
r = m_TMP1 % (-m_TMP2);
|
||||
}
|
||||
} else {
|
||||
if(m_TMP1 & 0x80000000) { // - +
|
||||
m_CCR |= F_N;
|
||||
q = -((-m_TMP1) / m_TMP2);
|
||||
r = (-m_TMP1) % m_TMP2;
|
||||
if(r) {
|
||||
r = m_TMP2 - r;
|
||||
q--;
|
||||
}
|
||||
r = -((-m_TMP1) % m_TMP2);
|
||||
} else { // + +
|
||||
q = m_TMP1 / m_TMP2;
|
||||
r = m_TMP1 % m_TMP2;
|
||||
}
|
||||
}
|
||||
if(q < 0)
|
||||
m_CCR |= F_N;
|
||||
r32_w(m_IR[1], (q & 0xffff) | ((r & 0xffff) << 16));
|
||||
}
|
||||
prefetch_done();
|
||||
|
@ -904,6 +904,8 @@ void swp00_device::keyon(int chan)
|
||||
m_lfo_phase[chan] = 0;
|
||||
m_sample_pos[chan] = -m_sample_start[chan] << 15;
|
||||
|
||||
m_sample_pos[chan] = 0;
|
||||
|
||||
m_active[chan] = true;
|
||||
m_decay[chan] = false;
|
||||
m_decay_done[chan] = false;
|
||||
@ -1324,6 +1326,7 @@ void swp00_device::sound_stream_update(sound_stream &stream, std::vector<read_st
|
||||
case 2: // 8-bits linear
|
||||
val0 = (read_byte(base_address + spos) << 8);
|
||||
val1 = (read_byte(base_address + spos + 1) << 8);
|
||||
logerror("XX %04x %04x\n", val0, val1);
|
||||
break;
|
||||
|
||||
case 3: { // 8-bits delta-pcm
|
||||
@ -1373,7 +1376,10 @@ void swp00_device::sound_stream_update(sound_stream &stream, std::vector<read_st
|
||||
m_lfo_phase[chan] = (m_lfo_phase[chan] + m_global_step[0x20 + (m_lfo_step[chan] & 0x3f)]) & 0x7ffffff;
|
||||
|
||||
u32 sample_increment = ((m_pitch[chan] & 0xfff) << (8 + (s16(m_pitch[chan]) >> 12))) >> 4;
|
||||
m_sample_pos[chan] += (sample_increment * (0x800 + ((lfo_p_phase * m_lfo_pmod_depth[chan]) >> (m_lfo_step[chan] & 0x40 ? 18 : 19)))) >> 11;
|
||||
m_sample_pos[chan] += 0x8000;//(sample_increment * (0x800 + ((lfo_p_phase * m_lfo_pmod_depth[chan]) >> (m_lfo_step[chan] & 0x40 ? 18 : 19)))) >> 11;
|
||||
(void)lfo_p_phase;
|
||||
(void)sample_increment;
|
||||
|
||||
if((m_sample_pos[chan] >> 15) >= m_sample_end[chan]) {
|
||||
if(!m_sample_end[chan])
|
||||
m_active[chan] = false;
|
||||
|
@ -1440,6 +1440,7 @@ void swp30_device::execute_run()
|
||||
break;
|
||||
}
|
||||
}
|
||||
logerror("XX %04x %04x\n", val0, val1);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,41 @@
|
||||
|
||||
DEFINE_DEVICE_TYPE(SWX00_SOUND, swx00_sound_device, "swx00_sound", "Yamaha SWX00 (sound subsystem)")
|
||||
|
||||
// Some tables we need. Lifted from the swp00, probably incorrect.
|
||||
|
||||
const std::array<s32, 0x80> swx00_sound_device::attack_linear_step = {
|
||||
0x00027, 0x0002b, 0x0002f, 0x00033, 0x00037, 0x0003d, 0x00042, 0x00048,
|
||||
0x0004d, 0x00056, 0x0005e, 0x00066, 0x0006f, 0x0007a, 0x00085, 0x00090,
|
||||
0x0009b, 0x000ac, 0x000bd, 0x000cc, 0x000de, 0x000f4, 0x00109, 0x00120,
|
||||
0x00135, 0x00158, 0x00179, 0x00199, 0x001bc, 0x001e7, 0x00214, 0x00240,
|
||||
0x0026b, 0x002af, 0x002f2, 0x00332, 0x00377, 0x003d0, 0x0042c, 0x00480,
|
||||
0x004dc, 0x0055e, 0x005e9, 0x0066e, 0x006f4, 0x007a4, 0x00857, 0x0090b,
|
||||
0x009c3, 0x00acb, 0x00bd6, 0x00ce6, 0x00e00, 0x00f5e, 0x010d2, 0x01234,
|
||||
0x0139e, 0x015d0, 0x017f3, 0x01a20, 0x01c4a, 0x01f52, 0x02232, 0x0250f,
|
||||
0x027ff, 0x02c72, 0x03109, 0x0338b, 0x039c4, 0x04038, 0x04648, 0x04c84,
|
||||
0x05262, 0x05c1c, 0x065af, 0x06f5c, 0x07895, 0x0866f, 0x09470, 0x0a19e,
|
||||
0x0ae4c, 0x0c566, 0x0db8d, 0x0f00f, 0x10625, 0x12937, 0x14954, 0x16c17,
|
||||
0x1886e, 0x1c71c, 0x20000, 0x239e1, 0x2647c, 0x2aaab, 0x2ecfc, 0x3241f,
|
||||
0x35e51, 0x3a83b, 0x40000, 0x4325c, 0x47dc1, 0x4c8f9, 0x50505, 0x55555,
|
||||
0x58160, 0x5d174, 0x60606, 0x62b2e, 0x67b24, 0x6a63c, 0x6d3a0, 0x6eb3e,
|
||||
0x71c72, 0x73616, 0x75075, 0x76b98, 0x78788, 0x78788, 0x7a44c, 0x7a44c,
|
||||
0x7a44c, 0x7a44c, 0x7a44c, 0x7a44c, 0x7a44c, 0x7a44c, 0x7a44c, 0x7a44c,
|
||||
};
|
||||
|
||||
const std::array<s32, 0x20> swx00_sound_device::decay_linear_step = {
|
||||
0x15083, 0x17ad2, 0x1a41a, 0x1cbe7, 0x1f16d, 0x22ef1, 0x26a44, 0x2a1e4,
|
||||
0x2da35, 0x34034, 0x3a197, 0x40000, 0x45b82, 0x4b809, 0x51833, 0x57262,
|
||||
0x5d9f7, 0x6483f, 0x6b15c, 0x71c72, 0x77976, 0x7d119, 0x83127, 0x88889,
|
||||
0x8d3dd, 0x939a8, 0x991f2, 0x9d89e, 0xa0a0a, 0xa57eb, 0xa72f0, 0xac769,
|
||||
};
|
||||
|
||||
const std::array<s32, 16> swx00_sound_device::panmap = {
|
||||
0x000, 0x040, 0x080, 0x0c0,
|
||||
0x100, 0x140, 0x180, 0x1c0,
|
||||
0x200, 0x240, 0x280, 0x2c0,
|
||||
0x300, 0x340, 0x380, 0xfff
|
||||
};
|
||||
|
||||
swx00_sound_device::swx00_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, SWX00_SOUND, tag, owner, clock),
|
||||
device_sound_interface(mconfig, *this),
|
||||
@ -22,6 +57,8 @@ void swx00_sound_device::device_add_mconfig(machine_config &config)
|
||||
|
||||
void swx00_sound_device::device_start()
|
||||
{
|
||||
m_stream = stream_alloc(0, 2, 44100);
|
||||
|
||||
save_item(NAME(m_sample_start));
|
||||
save_item(NAME(m_sample_end));
|
||||
save_item(NAME(m_sample_address));
|
||||
@ -31,7 +68,7 @@ void swx00_sound_device::device_start()
|
||||
save_item(NAME(m_cho_var));
|
||||
|
||||
save_item(NAME(m_attack));
|
||||
save_item(NAME(m_release));
|
||||
save_item(NAME(m_decay));
|
||||
|
||||
save_item(NAME(m_keyon));
|
||||
save_item(NAME(m_state_sel));
|
||||
@ -41,6 +78,43 @@ void swx00_sound_device::device_start()
|
||||
|
||||
save_item(NAME(m_rom_address));
|
||||
save_item(NAME(m_rom_read_status));
|
||||
|
||||
save_item(NAME(m_sample_pos));
|
||||
save_item(NAME(m_envelope_level));
|
||||
|
||||
save_item(NAME(m_glo_level_cur));
|
||||
save_item(NAME(m_pan_l));
|
||||
save_item(NAME(m_pan_r));
|
||||
|
||||
save_item(NAME(m_active));
|
||||
save_item(NAME(m_decay_on));
|
||||
save_item(NAME(m_decay_done));
|
||||
|
||||
save_item(NAME(m_dpcm_current));
|
||||
save_item(NAME(m_dpcm_next));
|
||||
save_item(NAME(m_dpcm_address));
|
||||
|
||||
|
||||
for(int i=0; i != 128; i++) {
|
||||
u32 v = 0;
|
||||
switch(i >> 3) {
|
||||
default: v = ((i & 7) + 8) << (1 + (i >> 3)); break;
|
||||
case 0xb: v = ((i & 7) + 4) << 13; break;
|
||||
case 0xc: v = ((i & 6) + 6) << 14; break;
|
||||
case 0xd: v = ((i & 4) + 7) << 15; break;
|
||||
case 0xe: v = 15 << 15; break;
|
||||
case 0xf: v = 31 << 15; break;
|
||||
}
|
||||
m_global_step[i] = v;
|
||||
}
|
||||
|
||||
// Delta-packed samples decompression.
|
||||
|
||||
for(int i=0; i<128; i++) {
|
||||
s16 base = ((i & 0x1f) << (5+(i >> 5))) + (((1 << (i >> 5))-1) << 10);
|
||||
m_dpcm[i | 0x80] = - base;
|
||||
m_dpcm[i] = + base;
|
||||
}
|
||||
}
|
||||
|
||||
void swx00_sound_device::device_reset()
|
||||
@ -54,26 +128,37 @@ void swx00_sound_device::device_reset()
|
||||
std::fill(m_cho_var.begin(), m_cho_var.end(), 0);
|
||||
|
||||
std::fill(m_attack.begin(), m_attack.end(), 0);
|
||||
std::fill(m_release.begin(), m_release.end(), 0);
|
||||
std::fill(m_decay.begin(), m_decay.end(), 0);
|
||||
|
||||
std::fill(m_dsp_offsets.begin(), m_dsp_offsets.end(), 0);
|
||||
std::fill(m_dsp_values.begin(), m_dsp_values.end(), 0);
|
||||
|
||||
std::fill(m_sample_pos.begin(), m_sample_pos.end(), 0);
|
||||
std::fill(m_envelope_level.begin(), m_envelope_level.end(), 0);
|
||||
|
||||
std::fill(m_glo_level_cur.begin(), m_glo_level_cur.end(), 0);
|
||||
std::fill(m_pan_l.begin(), m_pan_l.end(), 0);
|
||||
std::fill(m_pan_r.begin(), m_pan_r.end(), 0);
|
||||
|
||||
std::fill(m_active.begin(), m_active.end(), false);
|
||||
std::fill(m_decay_on.begin(), m_decay_on.end(), false);
|
||||
std::fill(m_decay_done.begin(), m_decay_done.end(), false);
|
||||
|
||||
std::fill(m_dpcm_current.begin(), m_dpcm_current.end(), false);
|
||||
std::fill(m_dpcm_next.begin(), m_dpcm_next.end(), false);
|
||||
std::fill(m_dpcm_address.begin(), m_dpcm_address.end(), false);
|
||||
|
||||
m_keyon = 0;
|
||||
m_state_sel = 0;
|
||||
m_rom_address = 0;
|
||||
m_rom_read_status = 0;
|
||||
}
|
||||
|
||||
void swx00_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
|
||||
{
|
||||
}
|
||||
|
||||
void swx00_sound_device::map(address_map &map)
|
||||
{
|
||||
map(0x000, 0x7ff).rw(FUNC(swx00_sound_device::snd_r), FUNC(swx00_sound_device::snd_w));
|
||||
|
||||
map(0x000, 0x000).rw(FUNC(swx00_sound_device::state_r), FUNC(swx00_sound_device::state_sel_w));
|
||||
map(0x001, 0x001).rw(FUNC(swx00_sound_device::state_r), FUNC(swx00_sound_device::state_sel_w));
|
||||
|
||||
map(0x008, 0x00b).w(FUNC(swx00_sound_device::keyon_w));
|
||||
map(0x00c, 0x00c).w(FUNC(swx00_sound_device::keyon_commit_w));
|
||||
@ -88,7 +173,7 @@ void swx00_sound_device::map(address_map &map)
|
||||
|
||||
rchan(map, 0x13).rw(FUNC(swx00_sound_device::glo_pan_r), FUNC(swx00_sound_device::glo_pan_w));
|
||||
rchan(map, 0x14).rw(FUNC(swx00_sound_device::attack_r), FUNC(swx00_sound_device::attack_w));
|
||||
rchan(map, 0x15).rw(FUNC(swx00_sound_device::release_r), FUNC(swx00_sound_device::release_w));
|
||||
rchan(map, 0x15).rw(FUNC(swx00_sound_device::decay_r), FUNC(swx00_sound_device::decay_w));
|
||||
rchan(map, 0x16).rw(FUNC(swx00_sound_device::rev_dry_r), FUNC(swx00_sound_device::rev_dry_w));
|
||||
rchan(map, 0x17).rw(FUNC(swx00_sound_device::cho_var_r), FUNC(swx00_sound_device::cho_var_w));
|
||||
rchan(map, 0x18).rw(FUNC(swx00_sound_device::sample_address_h_r), FUNC(swx00_sound_device::sample_address_h_w));
|
||||
@ -246,7 +331,35 @@ void swx00_sound_device::keyon_w(offs_t offset, u8 data)
|
||||
|
||||
void swx00_sound_device::keyon_commit_w(u8)
|
||||
{
|
||||
logerror("keyon commit %08x\n", m_keyon);
|
||||
m_stream->update();
|
||||
for(int chan = 0; chan != 32; chan++)
|
||||
if(BIT(m_keyon, chan)) {
|
||||
logerror("keyon %02x\n", chan);
|
||||
m_sample_pos[chan] = -m_sample_start[chan] << 15;
|
||||
|
||||
m_sample_pos[chan] = 0;
|
||||
|
||||
m_active[chan] = true;
|
||||
m_decay_on[chan] = false;
|
||||
m_decay_done[chan] = false;
|
||||
|
||||
m_dpcm_current[chan] = 0;
|
||||
m_dpcm_next[chan] = 0;
|
||||
m_dpcm_address[chan] = ((m_sample_address[chan] & 0xffffff) << 1) - m_sample_start[chan];
|
||||
|
||||
m_glo_level_cur[chan] = (m_glo_pan[chan] >> 4) & 0xff0;
|
||||
m_pan_l[chan] = panmap[(m_glo_pan[chan] >> 4) & 15];
|
||||
m_pan_r[chan] = panmap[m_glo_pan[chan] & 15];
|
||||
|
||||
if(m_decay[chan] & 0x8000) {
|
||||
m_envelope_level[chan] = 0;
|
||||
m_decay_on[chan] = true;
|
||||
} else if((m_attack[chan] & 0x8000) || (m_attack[chan] & 0xff))
|
||||
m_envelope_level[chan] = (m_attack[chan] & 0xff) << 20;
|
||||
else
|
||||
m_envelope_level[chan] = 0x8000000;
|
||||
}
|
||||
|
||||
m_keyon = 0;
|
||||
}
|
||||
|
||||
@ -262,16 +375,16 @@ void swx00_sound_device::attack_w(offs_t chan, u16 data, u16 mem_mask)
|
||||
logerror("%02x: attack %02x.%02x\n", chan, m_attack[chan] >> 8, m_attack[chan] & 0xff);
|
||||
}
|
||||
|
||||
u16 swx00_sound_device::release_r(offs_t chan)
|
||||
u16 swx00_sound_device::decay_r(offs_t chan)
|
||||
{
|
||||
return m_release[chan];
|
||||
return m_decay[chan];
|
||||
}
|
||||
|
||||
void swx00_sound_device::release_w(offs_t chan, u16 data, u16 mem_mask)
|
||||
void swx00_sound_device::decay_w(offs_t chan, u16 data, u16 mem_mask)
|
||||
{
|
||||
COMBINE_DATA(&m_release[chan]);
|
||||
COMBINE_DATA(&m_decay[chan]);
|
||||
if(ACCESSING_BITS_0_7)
|
||||
logerror("%02x: release %02x.%02x\n", chan, m_release[chan] >> 8, m_release[chan] & 0xff);
|
||||
logerror("%02x: decay %02x.%02x\n", chan, m_decay[chan] >> 8, m_decay[chan] & 0xff);
|
||||
}
|
||||
|
||||
void swx00_sound_device::state_sel_w(u8 data)
|
||||
@ -281,6 +394,30 @@ void swx00_sound_device::state_sel_w(u8 data)
|
||||
|
||||
u8 swx00_sound_device::state_r()
|
||||
{
|
||||
int chan = m_state_sel & 0x1f;
|
||||
switch(m_state_sel & 0xe0) {
|
||||
case 0x40: { // Envelope state
|
||||
if(!m_active[chan])
|
||||
return 0xff;
|
||||
|
||||
u8 vol;
|
||||
if(m_decay_on[chan] || (m_attack[chan] & 0x7f) || (m_attack[chan] & 0x8000))
|
||||
vol = m_envelope_level[chan] >> 22;
|
||||
else
|
||||
vol = 0;
|
||||
|
||||
if(m_decay_done[chan])
|
||||
vol |= 0x40;
|
||||
if(m_decay_on[chan])
|
||||
vol |= 0x80;
|
||||
|
||||
return vol;
|
||||
}
|
||||
|
||||
default:
|
||||
logerror("state_r %02x\n", m_state_sel);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -308,3 +445,267 @@ void swx00_sound_device::dsp_offl_w(offs_t reg, u8 data)
|
||||
} else
|
||||
m_dsp_offsets[reg >> 1] = (m_dsp_offh << 16) | (data << 8) | (m_dsp_offsets[reg >> 1] & 0xff);
|
||||
}
|
||||
|
||||
bool swx00_sound_device::istep(s32 &value, s32 limit, s32 step)
|
||||
{
|
||||
// fprintf(stderr, "istep(%x, %x, %x)\n", value, limit, step);
|
||||
if(value < limit) {
|
||||
value += step;
|
||||
if(value >= limit) {
|
||||
value = limit;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if(value > limit) {
|
||||
value -= step;
|
||||
if(value <= limit) {
|
||||
value = limit;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
s32 swx00_sound_device::fpadd(s32 value, s32 step)
|
||||
{
|
||||
s32 e = value >> 24;
|
||||
s32 m = value & 0xffffff;
|
||||
|
||||
m += step << e;
|
||||
if(m & 0xfe000000)
|
||||
return 0xfffffff;
|
||||
|
||||
while(m & 0x01000000) {
|
||||
m <<= 1;
|
||||
e ++;
|
||||
}
|
||||
if(e >= 16)
|
||||
return 0xfffffff;
|
||||
return (e << 24) | (m & 0xffffff);
|
||||
}
|
||||
|
||||
s32 swx00_sound_device::fpsub(s32 value, s32 step)
|
||||
{
|
||||
s32 e = value >> 24;
|
||||
s32 m = (value & 0xffffff) | 0xfe000000;
|
||||
m = e < 0xc ? m - (step << e) : (m >> (e - 0xb)) - (step << 0xb);
|
||||
if(m >= 0)
|
||||
return 0;
|
||||
if(e >= 0xc)
|
||||
e = 0xb;
|
||||
while(m < 0xfe000000) {
|
||||
if(!e)
|
||||
return 0;
|
||||
e --;
|
||||
m >>= 1;
|
||||
}
|
||||
while(e != 0xf && (m >= 0xff000000)) {
|
||||
e ++;
|
||||
m <<= 1;
|
||||
}
|
||||
|
||||
return (e << 24) | (m & 0xffffff);
|
||||
}
|
||||
|
||||
bool swx00_sound_device::fpstep(s32 &value, s32 limit, s32 step)
|
||||
{
|
||||
// value, limit and step are 4.24 but step has its exponent and
|
||||
// top four bits zero
|
||||
|
||||
if(value == limit)
|
||||
return true;
|
||||
if(value < limit) {
|
||||
value = fpadd(value, step);
|
||||
if(value >= limit) {
|
||||
value = limit;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
value = fpsub(value, step);
|
||||
if(value <= limit) {
|
||||
value = limit;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// sample is signed 24.8
|
||||
s32 swx00_sound_device::fpapply(s32 value, s32 sample)
|
||||
{
|
||||
if(value >= 0x10000000)
|
||||
return 0;
|
||||
return (s64(sample) - ((s64(sample) * ((value >> 9) & 0x7fff)) >> 16)) >> (value >> 24);
|
||||
}
|
||||
|
||||
void swx00_sound_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
|
||||
{
|
||||
for(int i=0; i != outputs[0].samples(); i++) {
|
||||
s32 dry_l = 0, dry_r = 0;
|
||||
s32 rev = 0;
|
||||
s32 cho_l = 0, cho_r = 0;
|
||||
s32 var_l = 0, var_r = 0;
|
||||
|
||||
for(int chan = 0; chan != 32; chan++) {
|
||||
if(!m_active[chan])
|
||||
continue;
|
||||
|
||||
s16 val0, val1;
|
||||
u32 base_address = m_sample_address[chan] & 0xffffff;
|
||||
s32 spos = m_sample_pos[chan] >> 15;
|
||||
switch(m_sample_address[chan] >> 30) {
|
||||
case 0: { // 16-bits linear
|
||||
offs_t adr = base_address + spos;
|
||||
val0 = read_word(adr);
|
||||
val1 = read_word(adr+1);
|
||||
break;
|
||||
}
|
||||
|
||||
case 1: { // 12-bits linear
|
||||
offs_t adr = base_address + (spos >> 2)*3;
|
||||
switch(spos & 3) {
|
||||
case 0: { // Cabc ..AB .... ....
|
||||
u16 w0 = read_word(adr);
|
||||
u16 w1 = read_word(adr+1);
|
||||
val0 = (w0 & 0x0fff) << 4;
|
||||
val1 = ((w0 & 0xf000) >> 8) | ((w1 & 0x00ff) << 8);
|
||||
break;
|
||||
}
|
||||
case 1: { // c... BCab ...A ....
|
||||
u16 w0 = read_word(adr);
|
||||
u16 w1 = read_word(adr+1);
|
||||
u16 w2 = read_word(adr+2);
|
||||
val0 = ((w0 & 0xf000) >> 8) | ((w1 & 0x00ff) << 8);
|
||||
val1 = ((w1 & 0xff00) >> 4) | ((w2 & 0x000f) << 12);
|
||||
break;
|
||||
}
|
||||
case 2: { // .... bc.. ABCa ....
|
||||
u16 w1 = read_word(adr+1);
|
||||
u16 w2 = read_word(adr+2);
|
||||
val0 = ((w1 & 0xff00) >> 4) | ((w2 & 0x000f) << 12);
|
||||
val1 = w2 & 0xfff0;
|
||||
break;
|
||||
}
|
||||
case 3: { // .... .... abc. .ABC
|
||||
u16 w2 = read_word(adr+2);
|
||||
u16 w3 = read_word(adr+3);
|
||||
val0 = w2 & 0xfff0;
|
||||
val1 = (w3 & 0x0fff) << 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: { // 8-bits linear
|
||||
offs_t adr = base_address + (spos >> 1);
|
||||
if(spos & 1) {
|
||||
u16 w0 = read_word(adr);
|
||||
u16 w1 = read_word(adr+1);
|
||||
val0 = w0 & 0xff00;
|
||||
val1 = w1 << 8;
|
||||
} else {
|
||||
u16 w0 = read_word(adr);
|
||||
val0 = w0 << 8;
|
||||
val1 = w0 & 0xff00;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 3: { // 8-bits delta-pcm
|
||||
u32 target_address = (base_address << 1) + spos + 1;
|
||||
while(m_dpcm_address[chan] <= target_address) {
|
||||
m_dpcm_current[chan] = m_dpcm_next[chan];
|
||||
u16 idx = read_word(m_dpcm_address[chan] >> 1);
|
||||
if(m_dpcm_address[chan] & 1)
|
||||
idx &= 0xff;
|
||||
else
|
||||
idx >>= 8;
|
||||
s32 sample = m_dpcm_next[chan] + m_dpcm[idx];
|
||||
m_dpcm_address[chan] ++;
|
||||
if(sample < -0x8000)
|
||||
sample = -0x8000;
|
||||
else if(sample > 0x7fff)
|
||||
sample = 0x7fff;
|
||||
m_dpcm_next[chan] = sample;
|
||||
}
|
||||
val0 = m_dpcm_current[chan];
|
||||
val1 = m_dpcm_next[chan];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
s32 mul = m_sample_pos[chan] & 0x7fff;
|
||||
s32 sample = (val1 * mul + val0 * (0x8000 - mul)) >> 7;
|
||||
|
||||
s32 envelope_level;
|
||||
if(m_decay_on[chan] || (m_attack[chan] & 0xff) || (m_attack[chan] & 0x8000))
|
||||
envelope_level = m_envelope_level[chan];
|
||||
else
|
||||
envelope_level = 0;
|
||||
|
||||
s32 tremolo_level = 0;
|
||||
|
||||
dry_l += fpapply(envelope_level + (m_glo_level_cur[chan] << 16) + tremolo_level + ((m_rev_dry[chan] << 20) & 0xff00000) + (m_pan_l[chan] << 16), sample);
|
||||
dry_r += fpapply(envelope_level + (m_glo_level_cur[chan] << 16) + tremolo_level + ((m_rev_dry[chan] << 20) & 0xff00000) + (m_pan_r[chan] << 16), sample);
|
||||
rev += fpapply(envelope_level + (m_glo_level_cur[chan] << 16) + tremolo_level + ((m_rev_dry[chan] << 12) & 0xff00000), sample);
|
||||
cho_l += fpapply(envelope_level + (m_glo_level_cur[chan] << 16) + tremolo_level + ((m_cho_var[chan] << 12) & 0xff00000) + (m_pan_l[chan] << 16), sample);
|
||||
cho_r += fpapply(envelope_level + (m_glo_level_cur[chan] << 16) + tremolo_level + ((m_cho_var[chan] << 12) & 0xff00000) + (m_pan_r[chan] << 16), sample);
|
||||
var_l += fpapply(envelope_level + (m_glo_level_cur[chan] << 16) + tremolo_level + ((m_cho_var[chan] << 20) & 0xff00000) + (m_pan_l[chan] << 16), sample);
|
||||
var_r += fpapply(envelope_level + (m_glo_level_cur[chan] << 16) + tremolo_level + ((m_cho_var[chan] << 20) & 0xff00000) + (m_pan_r[chan] << 16), sample);
|
||||
|
||||
u32 sample_increment = ((m_sample_pitch[chan] & 0xfff) << (8 + (s16(m_sample_pitch[chan]) >> 12))) >> 4;
|
||||
m_sample_pos[chan] += sample_increment;
|
||||
if((m_sample_pos[chan] >> 15) >= m_sample_end[chan]) {
|
||||
if(!m_sample_end[chan])
|
||||
m_active[chan] = false;
|
||||
else {
|
||||
s32 prev = m_sample_pos[chan];
|
||||
do
|
||||
m_sample_pos[chan] -= (m_sample_end[chan] << 15) | ((m_sample_address[chan] & 0x3f000000) >> (24-9));
|
||||
while((m_sample_pos[chan] >> 15) >= m_sample_end[chan]);
|
||||
m_dpcm_address[chan] += (m_sample_pos[chan] >> 15) - (prev >> 15);
|
||||
}
|
||||
}
|
||||
|
||||
istep(m_glo_level_cur[chan], (m_glo_pan[chan] >> 4) & 0xff0, 1);
|
||||
istep(m_pan_l[chan], panmap[(m_glo_pan[chan] >> 4) & 15], 1);
|
||||
istep(m_pan_r[chan], panmap[m_glo_pan[chan] & 15], 1);
|
||||
|
||||
if(m_decay_on[chan]) {
|
||||
if((m_decay[chan] & 0x6000) == 0x6000)
|
||||
m_decay_done[chan] = fpstep(m_envelope_level[chan], (m_decay[chan] & 0xff) << 20, decay_linear_step[(m_decay[chan] >> 8) & 0x1f]);
|
||||
else
|
||||
m_decay_done[chan] = istep(m_envelope_level[chan], (m_decay[chan] & 0xff) << 20, m_global_step[m_decay[chan] >> 8] << 1);
|
||||
if(m_envelope_level[chan] & 0x8000000)
|
||||
m_active[chan] = false;
|
||||
|
||||
} else if(m_attack[chan] & 0x8000)
|
||||
m_decay_on[chan] = fpstep(m_envelope_level[chan], 0, attack_linear_step[(m_attack[chan] >> 8) & 0x7f]);
|
||||
else
|
||||
m_decay_on[chan] = istep(m_envelope_level[chan], 0, m_global_step[m_attack[chan] >> 8] << 1);
|
||||
}
|
||||
|
||||
dry_l >>= 8;
|
||||
dry_r >>= 8;
|
||||
rev >>= 8;
|
||||
cho_l >>= 8;
|
||||
cho_r >>= 8;
|
||||
var_l >>= 8;
|
||||
var_r >>= 8;
|
||||
|
||||
(void)rev;
|
||||
(void)cho_l;
|
||||
(void)cho_r;
|
||||
(void)var_l;
|
||||
(void)var_r;
|
||||
|
||||
outputs[0].put_int(i, dry_l, 32768);
|
||||
outputs[1].put_int(i, dry_r, 32768);
|
||||
}
|
||||
}
|
||||
|
@ -25,21 +25,39 @@ protected:
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
|
||||
private:
|
||||
sound_stream *m_stream;
|
||||
|
||||
static const std::array<s32, 0x80> attack_linear_step;
|
||||
static const std::array<s32, 0x20> decay_linear_step;
|
||||
static const std::array<s32, 16> panmap;
|
||||
std::array<s32, 0x80> m_global_step;
|
||||
std::array<s16, 0x100> m_dpcm;
|
||||
|
||||
std::array<u16, 0x20> m_sample_start;
|
||||
std::array<u16, 0x20> m_sample_end;
|
||||
std::array<u32, 0x20> m_sample_address;
|
||||
std::array<u16, 0x20> m_sample_pitch;
|
||||
|
||||
std::array<u16, 0x20> m_attack;
|
||||
std::array<u16, 0x20> m_release;
|
||||
std::array<u16, 0x20> m_decay;
|
||||
|
||||
std::array<u16, 0x20> m_glo_pan;
|
||||
std::array<u16, 0x20> m_rev_dry;
|
||||
std::array<u16, 0x20> m_cho_var;
|
||||
|
||||
std::array<u32, 0x40> m_dsp_offsets;
|
||||
std::array<u32, 0x40> m_dsp_offsets;
|
||||
std::array<u16, 0x120> m_dsp_values;
|
||||
|
||||
std::array<s32, 0x20> m_sample_pos;
|
||||
std::array<s32, 0x20> m_envelope_level;
|
||||
std::array<s32, 0x20> m_glo_level_cur;
|
||||
std::array<s32, 0x20> m_pan_l;
|
||||
std::array<s32, 0x20> m_pan_r;
|
||||
std::array<bool, 0x20> m_active, m_decay_on, m_decay_done;
|
||||
std::array<s16, 0x20> m_dpcm_current;
|
||||
std::array<s16, 0x20> m_dpcm_next;
|
||||
std::array<u32, 0x20> m_dpcm_address;
|
||||
|
||||
u32 m_keyon;
|
||||
u32 m_rom_address;
|
||||
u16 m_rom_read_status;
|
||||
@ -74,8 +92,8 @@ private:
|
||||
|
||||
u16 attack_r(offs_t chan);
|
||||
void attack_w(offs_t chan, u16 data, u16 mem_mask);
|
||||
u16 release_r(offs_t chan);
|
||||
void release_w(offs_t chan, u16 data, u16 mem_mask);
|
||||
u16 decay_r(offs_t chan);
|
||||
void decay_w(offs_t chan, u16 data, u16 mem_mask);
|
||||
|
||||
void keyon_w(offs_t offset, u8 data);
|
||||
void keyon_commit_w(u8);
|
||||
@ -93,6 +111,12 @@ private:
|
||||
|
||||
void state_sel_w(u8 data);
|
||||
u8 state_r();
|
||||
|
||||
static bool istep(s32 &value, s32 limit, s32 step);
|
||||
static bool fpstep(s32 &value, s32 limit, s32 step);
|
||||
static s32 fpadd(s32 value, s32 step);
|
||||
static s32 fpsub(s32 value, s32 step);
|
||||
static s32 fpapply(s32 value, s32 sample);
|
||||
};
|
||||
|
||||
DECLARE_DEVICE_TYPE(SWX00_SOUND, swx00_sound_device)
|
||||
|
@ -160,7 +160,6 @@ void mks3_device::req_w(int state)
|
||||
|
||||
TIMER_CALLBACK_MEMBER(mks3_device::transmit_tick)
|
||||
{
|
||||
logerror("tr %d\n", m_step);
|
||||
if(m_step == 15) {
|
||||
transmit_next();
|
||||
return;
|
||||
@ -189,7 +188,6 @@ void mks3_device::transmit_next()
|
||||
if(m_byte_count)
|
||||
memmove(m_bytes.data(), m_bytes.data() + 1, m_byte_count);
|
||||
|
||||
logerror("start %02x\n", m_byte);
|
||||
m_write_clk(0);
|
||||
m_write_da(BIT(m_byte, 7));
|
||||
m_step = 0;
|
||||
|
@ -4,16 +4,12 @@
|
||||
Yamaha PSR-340 PortaSound keyboard
|
||||
Preliminary driver by R. Belmont
|
||||
|
||||
CPU and Sound: SWX00B, which is an H8S/2000 series CPU and Yamaha SWP00? (or SWP30?) on one chip.
|
||||
CPU and Sound: SWX00B, which is an H8S/2000 series CPU and Yamaha
|
||||
AWM2 with capabilities somewhat intermediate between SWP00 and
|
||||
SWP30.
|
||||
LCD controller: KS0066U (apparently equivalent to Samsung S6A0069)
|
||||
FDC: HD63266F (uPD765 derivative)
|
||||
RAM: 256KiB, 2x uPD431000 or equivalent
|
||||
|
||||
TODO:
|
||||
- Customized CPU. Interrupt controller is H8S/2655 style, but there are customizations too.
|
||||
- LCD (it's similar to the MU-5's)
|
||||
- Front panel / keyboard scanner (6305 with internal ROM manages this on hardware)
|
||||
- Sound generation
|
||||
*/
|
||||
|
||||
#include "emu.h"
|
||||
|
Loading…
Reference in New Issue
Block a user