diff options
Diffstat (limited to 'src/mame/audio/flower.cpp')
-rw-r--r-- | src/mame/audio/flower.cpp | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/src/mame/audio/flower.cpp b/src/mame/audio/flower.cpp new file mode 100644 index 00000000000..f830ac2d2b3 --- /dev/null +++ b/src/mame/audio/flower.cpp @@ -0,0 +1,281 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese +/*************************************************************************** + + Flower custom sound chip + + Similar to Wiping and Namco 15xx designs + + TODO: + - several unknown registers (effects and unknown register tied to repeat port); + - repeat certainly needs a cutoff, which is unknown about how it works; + +***************************************************************************/ + +#include "emu.h" +#include "flower.h" + + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// device type definition +DEFINE_DEVICE_TYPE(FLOWER_CUSTOM, flower_sound_device, "flower", "Flower Custom Audio") + +// TODO: AM_SELECT unsupported by DEVICE_ADDRESS_MAP, so we need a trampoline here +static ADDRESS_MAP_START( regs_map, AS_IO, 8, flower_sound_device ) + AM_RANGE(0x00, 0x03) AM_SELECT(0x38) AM_WRITE(frequency_w) + AM_RANGE(0x04, 0x04) AM_SELECT(0x38) AM_WRITE(repeat_w) + AM_RANGE(0x05, 0x05) AM_SELECT(0x38) AM_WRITE(unk_w) + AM_RANGE(0x07, 0x07) AM_SELECT(0x38) AM_WRITE(volume_w) + AM_RANGE(0x40, 0x45) AM_SELECT(0x38) AM_WRITE(start_address_w) + AM_RANGE(0x47, 0x47) AM_SELECT(0x38) AM_WRITE(sample_trigger_w) +ADDRESS_MAP_END + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// flower_sound_device - constructor +//------------------------------------------------- + +flower_sound_device::flower_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, FLOWER_CUSTOM, tag, owner, clock), + device_sound_interface(mconfig, *this), + device_memory_interface(mconfig, *this), + m_io_space_config("io", ENDIANNESS_LITTLE, 8, 7, 0, *ADDRESS_MAP_NAME(regs_map)), + m_stream(nullptr), + m_mixer_table(nullptr), + m_mixer_lookup(nullptr), + m_mixer_buffer(nullptr), + m_last_channel(nullptr) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void flower_sound_device::device_start() +{ + int i; + m_iospace = &space(AS_IO); + // TODO: clock + m_stream = machine().sound().stream_alloc(*this, 0, 1, samplerate); + + m_mixer_buffer = make_unique_clear<short[]>(samplerate); + make_mixer_table(MAX_VOICES, defgain); + + m_last_channel = m_channel_list + MAX_VOICES; + + m_sample_rom = machine().root_device().memregion("samples")->base(); + m_volume_rom = machine().root_device().memregion("soundvol")->base(); + + for (i = 0; i < MAX_VOICES; i++) + { + save_item(NAME(m_channel_list[i].start_address), i); + save_item(NAME(m_channel_list[i].position), i); + save_item(NAME(m_channel_list[i].frequency), i); + save_item(NAME(m_channel_list[i].volume), i); + save_item(NAME(m_channel_list[i].volume_bank), i); + save_item(NAME(m_channel_list[i].effect), i); + save_item(NAME(m_channel_list[i].enable), i); + save_item(NAME(m_channel_list[i].repeat), i); + + // assign a channel number (debugger aid) + m_channel_list[i].channel_number = i; + } +} + + +/* build a table to divide by the number of voices; gain is specified as gain*16 */ +void flower_sound_device::make_mixer_table(int voices, int gain) +{ + int count = voices * 128; + int i; + + /* allocate memory */ + m_mixer_table = make_unique_clear<int16_t[]>(256 * voices); + + /* find the middle of the table */ + m_mixer_lookup = m_mixer_table.get() + (128 * voices); + + /* fill in the table - 16 bit case */ + for (i = 0; i < count; i++) + { + int val = i * gain * 16 / voices; + if (val > 32767) val = 32767; + m_mixer_lookup[ i] = val; + m_mixer_lookup[-i] = -val; + } +} + + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void flower_sound_device::device_reset() +{ + for (fl_sound_channel *voice = m_channel_list; voice < m_last_channel; voice++) + { + voice->start_address = 0; + voice->position = 0; + voice->volume = 0; + voice->enable = false; + voice->repeat = false; + } +} + +void flower_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + stream_sample_t *buffer = outputs[0]; + short *mix; + uint8_t raw_sample; + + memset(m_mixer_buffer.get(), 0, samples * sizeof(short)); + + for (fl_sound_channel *voice = m_channel_list; voice < m_last_channel; voice++) + { + int ch_volume = voice->volume; + int ch_frequency = voice->frequency; + + if(voice->enable == false) + continue; + + mix = m_mixer_buffer.get(); + + for(int i=0;i<samples;i++) + { + if(voice->repeat == true) + { + raw_sample = m_sample_rom[((voice->start_address >> 7) & 0x7e00) | ((voice->position >> 7) & 0x1ff)]; + // guess: cut off after a number of repetitions + if((voice->position >> 7) & 0x20000) + { + voice->enable = false; + break; + } + } + else + { + raw_sample = m_sample_rom[((voice->start_address + voice->position) >> 7) & 0x7fff]; + if(raw_sample == 0xff) + { + voice->enable = false; + break; + } + } + ch_volume |= voice->volume_bank; + + *mix++ += m_volume_rom[(ch_volume << 8 | raw_sample) & 0x3fff] - 0x80; + voice->position += ch_frequency; + } + } + + + + /* mix it down */ + mix = m_mixer_buffer.get(); + for (int i = 0; i < samples; i++) + *buffer++ = m_mixer_lookup[*mix++]; +} + +//------------------------------------------------- +// memory_space_config - return a description of +// any address spaces owned by this device +//------------------------------------------------- + +device_memory_interface::space_config_vector flower_sound_device::memory_space_config() const +{ + return space_config_vector { + std::make_pair(AS_IO, &m_io_space_config) + }; +} + +//************************************************************************** +// READ/WRITE HANDLERS +//************************************************************************** + +WRITE8_MEMBER( flower_sound_device::lower_write ) +{ + m_stream->update(); + m_iospace->write_byte(offset,data); +} + +WRITE8_MEMBER( flower_sound_device::upper_write ) +{ + m_stream->update(); + m_iospace->write_byte(offset|0x40,data); +} + +WRITE8_MEMBER( flower_sound_device::frequency_w ) +{ + uint8_t ch = (offset >> 3) & 0x7; + fl_sound_channel *voice; + + voice = &m_channel_list[ch]; + + voice->raw_frequency[offset & 3] = data & 0xf; + + voice->frequency = voice->raw_frequency[2] << 12; + voice->frequency|= voice->raw_frequency[3] << 8; + voice->frequency|= voice->raw_frequency[0] << 4; + voice->frequency|= voice->raw_frequency[1] << 0; +} + +WRITE8_MEMBER( flower_sound_device::repeat_w ) +{ + uint8_t ch = (offset >> 3) & 0x7; + fl_sound_channel *voice; + + voice = &m_channel_list[ch]; + voice->repeat = BIT(data,4); +} + +WRITE8_MEMBER( flower_sound_device::unk_w ) +{ + // same as above? +} + +WRITE8_MEMBER( flower_sound_device::volume_w ) +{ + uint8_t ch = (offset >> 3) & 0x7; + fl_sound_channel *voice; + + voice = &m_channel_list[ch]; + voice->volume = data >> 4; +} + +WRITE8_MEMBER( flower_sound_device::start_address_w ) +{ + uint8_t ch = (offset >> 3) & 0x7; + fl_sound_channel *voice; + + voice = &m_channel_list[ch]; + voice->start_nibbles[offset & 7] = data & 0xf; + if(offset == 4) + voice->effect = data >> 4; +} + +WRITE8_MEMBER( flower_sound_device::sample_trigger_w ) +{ + uint8_t ch = (offset >> 3) & 0x7; + fl_sound_channel *voice; + + voice = &m_channel_list[ch]; + + voice->enable = true; + voice->volume_bank = (data & 3) << 4; + voice->start_address = 0; + voice->position = 0; + for(int i=5;i>=0;i--) + { + voice->start_address = (voice->start_address << 4) | voice->start_nibbles[i]; + } +} |