diff options
Diffstat (limited to 'src/devices/sound/k051649.cpp')
-rw-r--r-- | src/devices/sound/k051649.cpp | 178 |
1 files changed, 71 insertions, 107 deletions
diff --git a/src/devices/sound/k051649.cpp b/src/devices/sound/k051649.cpp index 29287ba63f9..c4dd31c1ba7 100644 --- a/src/devices/sound/k051649.cpp +++ b/src/devices/sound/k051649.cpp @@ -1,6 +1,6 @@ // license:BSD-3-Clause // copyright-holders:Bryan McPhail -/*************************************************************************** +/******************************************************************************* Konami 051649 - SCC1 sound as used in Haunted Castle, City Bomber @@ -12,25 +12,30 @@ waveform from RAM (32 bytes per waveform, 8 bit signed data). This sound chip is the same as the sound chip in some Konami - megaROM cartridges for the MSX. It is actually well researched - and documented: + megaROM cartridges for the MSX. This device only emulates the + sound portion, not the memory mapper. - http://bifi.msxnet.org/msxnet/tech/scc.html + 052539 is more or less equivalent to this chip except channel 5 + does not share waveram with channel 4. - Thanks to Sean Young (sean@mess.org) for some bugfixes. + References: + - http://bifi.msxnet.org/msxnet/tech/scc.html + - http://bifi.msxnet.org/msxnet/tech/soundcartridge - K052539 is more or less equivalent to this chip except channel 5 - does not share waveram with channel 4. + TODO: + - make 052539 a subdevice + - bus conflicts on 051649 (not 052539). When the CPU accesses waveform RAM + and the SCC is reading it at the same time, it can cause audible spikes. + A similar thing happens internally when the shared ch4/ch5 do a read at + the same time. + - test register bits 0-4, not used in any software -***************************************************************************/ +*******************************************************************************/ #include "emu.h" #include "k051649.h" #include <algorithm> -#define FREQ_BITS 16 -#define DEF_GAIN 8 - void k051649_device::scc_map(address_map &map) { map(0x00, 0x7f).rw(FUNC(k051649_device::k051649_waveform_r), FUNC(k051649_device::k051649_waveform_w)); @@ -44,9 +49,9 @@ void k051649_device::scc_map(address_map &map) DEFINE_DEVICE_TYPE(K051649, k051649_device, "k051649", "K051649 SCC1") -//************************************************************************** +//****************************************************************************** // LIVE DEVICE -//************************************************************************** +//****************************************************************************** //------------------------------------------------- // k051649_device - constructor @@ -56,10 +61,6 @@ k051649_device::k051649_device(const machine_config &mconfig, const char *tag, d : device_t(mconfig, K051649, tag, owner, clock) , device_sound_interface(mconfig, *this) , m_stream(nullptr) - , m_mclock(0) - , m_rate(0) - , m_mixer_table(nullptr) - , m_mixer_lookup(nullptr) , m_test(0) { } @@ -72,25 +73,16 @@ k051649_device::k051649_device(const machine_config &mconfig, const char *tag, d void k051649_device::device_start() { // get stream channels - m_rate = clock()/16; - m_stream = stream_alloc(0, 1, m_rate); - m_mclock = clock(); - - // allocate a buffer to mix into - 1 second's worth should be more than enough - m_mixer_buffer.resize(2 * m_rate); - - // build the mixer table - make_mixer_table(5); + m_stream = stream_alloc(0, 1, clock()); // save states - for (int voice = 0; voice < 5; voice++) - { - save_item(NAME(m_channel_list[voice].counter), voice); - save_item(NAME(m_channel_list[voice].frequency), voice); - save_item(NAME(m_channel_list[voice].volume), voice); - save_item(NAME(m_channel_list[voice].key), voice); - save_item(NAME(m_channel_list[voice].waveram), voice); - } + save_item(STRUCT_MEMBER(m_channel_list, counter)); + save_item(STRUCT_MEMBER(m_channel_list, clock)); + save_item(STRUCT_MEMBER(m_channel_list, frequency)); + save_item(STRUCT_MEMBER(m_channel_list, volume)); + save_item(STRUCT_MEMBER(m_channel_list, sample)); + save_item(STRUCT_MEMBER(m_channel_list, key)); + save_item(STRUCT_MEMBER(m_channel_list, waveram)); save_item(NAME(m_test)); } @@ -107,6 +99,7 @@ void k051649_device::device_reset() voice.frequency = 0; voice.volume = 0xf; voice.counter = 0; + voice.clock = 0; voice.key = false; } @@ -132,15 +125,7 @@ void k051649_device::device_post_load() void k051649_device::device_clock_changed() { - const u32 old_rate = m_rate; - m_rate = clock()/16; - m_mclock = clock(); - - if (old_rate < m_rate) - { - m_mixer_buffer.resize(2 * m_rate, 0); - } - m_stream->set_sample_rate(m_rate); + m_stream->set_sample_rate(clock()); } @@ -148,41 +133,34 @@ void k051649_device::device_clock_changed() // sound_stream_update - handle a stream update //------------------------------------------------- -void k051649_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +void k051649_device::sound_stream_update(sound_stream &stream) { - // zap the contents of the mixer buffer - std::fill(m_mixer_buffer.begin(), m_mixer_buffer.end(), 0); - - for (sound_channel &voice : m_channel_list) + for (int i = 0; i < stream.samples(); i++) { - // channel is halted for freq < 9 - if (voice.frequency > 8) + for (sound_channel &voice : m_channel_list) { - const int v = voice.volume * voice.key; - int c = voice.counter; - const int step = ((s64(m_mclock) << FREQ_BITS) / float((voice.frequency + 1) * 16 * (m_rate / 32))) + 0.5f; - - // add our contribution - for (int i = 0; i < samples; i++) + // channel is halted for freq < 9 + if (voice.frequency > 8) { - c += step; - const int offs = (c >> FREQ_BITS) & 0x1f; - m_mixer_buffer[i] += (voice.waveram[offs] * v) >> 3; + if (++voice.clock > voice.frequency) + { + voice.counter = (voice.counter + 1) & 0x1f; + voice.clock = 0; + } + if (voice.clock == 0) + { + voice.sample = (voice.key ? voice.waveram[voice.counter] : 0) * voice.volume; + } } - // update the counter for this voice - voice.counter = c; + // scale to 11 bit digital output on chip + stream.add_int(0, i, voice.sample >> 4, 1024); } } - - // mix it down - stream_sample_t *buffer = outputs[0]; - for (int i = 0; i < samples; i++) - *buffer++ = m_mixer_lookup[m_mixer_buffer[i]]; } -/********************************************************************************/ +/******************************************************************************/ void k051649_device::k051649_waveform_w(offs_t offset, u8 data) @@ -206,17 +184,19 @@ void k051649_device::k051649_waveform_w(offs_t offset, u8 data) u8 k051649_device::k051649_waveform_r(offs_t offset) { - // test-register bits 6/7 expose the internal counter + u8 counter = 0; + + // test register bits 6/7 expose the internal counter if (m_test & 0xc0) { m_stream->update(); - if (offset >= 0x60) - offset += (m_channel_list[3 + (m_test >> 6 & 1)].counter >> FREQ_BITS); + if (offset >= 0x60 && (m_test & 0xc0) != 0xc0) + counter = m_channel_list[3 + (m_test >> 6 & 1)].counter; else if (m_test & 0x40) - offset += (m_channel_list[offset >> 5].counter >> FREQ_BITS); + counter = m_channel_list[offset >> 5].counter; } - return m_channel_list[offset >> 5].waveram[offset & 0x1f]; + return m_channel_list[offset >> 5].waveram[(offset + counter) & 0x1f]; } @@ -233,20 +213,22 @@ void k051649_device::k052539_waveform_w(offs_t offset, u8 data) u8 k051649_device::k052539_waveform_r(offs_t offset) { - // test-register bit 6 exposes the internal counter + u8 counter = 0; + + // test register bit 6 exposes the internal counter if (m_test & 0x40) { m_stream->update(); - offset += (m_channel_list[offset >> 5].counter >> FREQ_BITS); + counter = m_channel_list[offset >> 5].counter; } - return m_channel_list[offset >> 5].waveram[offset & 0x1f]; + return m_channel_list[offset >> 5].waveram[(offset + counter) & 0x1f]; } void k051649_device::k051649_volume_w(offs_t offset, u8 data) { m_stream->update(); - m_channel_list[offset & 0x7].volume = data & 0xf; + m_channel_list[offset].volume = data & 0xf; } @@ -257,17 +239,18 @@ void k051649_device::k051649_frequency_w(offs_t offset, u8 data) m_stream->update(); - // test-register bit 5 resets the internal counter - if (m_test & 0x20) - m_channel_list[offset].counter = ~0; - else if (m_channel_list[offset].frequency < 9) - m_channel_list[offset].counter |= ((1 << FREQ_BITS) - 1); - // update frequency if (freq_hi) m_channel_list[offset].frequency = (m_channel_list[offset].frequency & 0x0ff) | (data << 8 & 0xf00); else m_channel_list[offset].frequency = (m_channel_list[offset].frequency & 0xf00) | data; + + // test register bit 5 resets the internal counter + if (m_test & 0x20) + m_channel_list[offset].counter = 0; + + // sample reload pending + m_channel_list[offset].clock = -1; } @@ -288,32 +271,13 @@ void k051649_device::k051649_test_w(u8 data) } -u8 k051649_device::k051649_test_r() -{ - // reading the test register sets it to $ff! - if (!machine().side_effects_disabled()) - k051649_test_w(0xff); - return 0xff; -} - - -//------------------------------------------------- -// build a table to divide by the number of voices -//------------------------------------------------- - -void k051649_device::make_mixer_table(int voices) +u8 k051649_device::k051649_test_r(address_space &space) { - // allocate memory - m_mixer_table = std::make_unique<s16[]>(512 * voices); + u8 data = space.unmap(); - // find the middle of the table - m_mixer_lookup = m_mixer_table.get() + (256 * voices); + // reading the test register triggers a write + if (!machine().side_effects_disabled()) + k051649_test_w(data); - // fill in the table - 16 bit case - for (int i = 0; i < (voices * 256); i++) - { - const int val = std::min(32767, i * DEF_GAIN * 16 / voices); - m_mixer_lookup[ i] = val; - m_mixer_lookup[-i] = -val; - } + return data; } |