mirror of
https://github.com/holub/mame
synced 2025-10-05 08:41:31 +03:00
flower.cpp: rewrote custom sound device (nw)
This commit is contained in:
parent
6364a6f42a
commit
c4cd603431
@ -4524,6 +4524,7 @@ files {
|
||||
MAME_DIR .. "src/mame/drivers/fireball.cpp",
|
||||
MAME_DIR .. "src/mame/drivers/flipjack.cpp",
|
||||
MAME_DIR .. "src/mame/drivers/flower.cpp",
|
||||
MAME_DIR .. "src/mame/audio/flower.cpp",
|
||||
MAME_DIR .. "src/mame/drivers/fortecar.cpp",
|
||||
MAME_DIR .. "src/mame/drivers/fresh.cpp",
|
||||
MAME_DIR .. "src/mame/drivers/freekick.cpp",
|
||||
|
281
src/mame/audio/flower.cpp
Normal file
281
src/mame/audio/flower.cpp
Normal file
@ -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];
|
||||
}
|
||||
}
|
106
src/mame/audio/flower.h
Normal file
106
src/mame/audio/flower.h
Normal file
@ -0,0 +1,106 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Angelo Salese
|
||||
/***************************************************************************
|
||||
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MAME_AUDIO_FLOWER_H
|
||||
#define MAME_AUDIO_FLOWER_H
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// INTERFACE CONFIGURATION MACROS
|
||||
//**************************************************************************
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
// ======================> flower_sound_device
|
||||
|
||||
class flower_sound_device : public device_t,
|
||||
public device_sound_interface,
|
||||
public device_memory_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
flower_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
// I/O operations
|
||||
DECLARE_WRITE8_MEMBER( lower_write );
|
||||
DECLARE_WRITE8_MEMBER( upper_write );
|
||||
// virtual DECLARE_ADDRESS_MAP(lower_map, 8);
|
||||
// virtual DECLARE_ADDRESS_MAP(upper_map, 8);
|
||||
DECLARE_WRITE8_MEMBER( frequency_w );
|
||||
DECLARE_WRITE8_MEMBER( repeat_w );
|
||||
DECLARE_WRITE8_MEMBER( unk_w );
|
||||
DECLARE_WRITE8_MEMBER( volume_w );
|
||||
DECLARE_WRITE8_MEMBER( start_address_w );
|
||||
DECLARE_WRITE8_MEMBER( sample_trigger_w );
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
//virtual void device_validity_check(validity_checker &valid) const override;
|
||||
//virtual void device_add_mconfig(machine_config &config) override;
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
virtual space_config_vector memory_space_config() const override;
|
||||
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
|
||||
|
||||
address_space *m_iospace;
|
||||
private:
|
||||
|
||||
const address_space_config m_io_space_config;
|
||||
sound_stream *m_stream;
|
||||
|
||||
static constexpr unsigned MAX_VOICES = 8;
|
||||
static constexpr int samplerate = 48000;
|
||||
static constexpr int defgain = 48;
|
||||
|
||||
std::unique_ptr<int16_t[]> m_mixer_table;
|
||||
int16_t *m_mixer_lookup;
|
||||
std::unique_ptr<short[]> m_mixer_buffer;
|
||||
|
||||
struct fl_sound_channel
|
||||
{
|
||||
uint8_t start_nibbles[6];
|
||||
uint8_t raw_frequency[4];
|
||||
uint32_t start_address;
|
||||
uint32_t position;
|
||||
uint16_t frequency;
|
||||
uint8_t volume;
|
||||
uint8_t volume_bank;
|
||||
uint8_t effect;
|
||||
bool enable;
|
||||
bool repeat;
|
||||
int channel_number;
|
||||
};
|
||||
|
||||
/* data about the sound system */
|
||||
fl_sound_channel m_channel_list[MAX_VOICES];
|
||||
fl_sound_channel *m_last_channel;
|
||||
|
||||
void make_mixer_table(int voices, int gain);
|
||||
|
||||
const uint8_t *m_sample_rom;
|
||||
const uint8_t *m_volume_rom;
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(FLOWER_CUSTOM, flower_sound_device)
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// GLOBAL VARIABLES
|
||||
//**************************************************************************
|
||||
|
||||
|
||||
#endif // MAME_MACHINE_FLOWER_H
|
@ -81,7 +81,7 @@ CHIP # POSITION TYPE
|
||||
#include "emu.h"
|
||||
#include "cpu/z80/z80.h"
|
||||
#include "machine/gen_latch.h"
|
||||
#include "audio/wiping.h"
|
||||
#include "audio/flower.h"
|
||||
#include "screen.h"
|
||||
#include "speaker.h"
|
||||
|
||||
@ -359,9 +359,8 @@ static ADDRESS_MAP_START( audio_map, AS_PROGRAM, 8, flower_state )
|
||||
AM_RANGE(0x4000, 0x4000) AM_WRITENOP // audio irq related (0 at start, 1 at end)
|
||||
AM_RANGE(0x4001, 0x4001) AM_WRITE(audio_nmi_mask_w)
|
||||
AM_RANGE(0x6000, 0x6000) AM_DEVREAD("soundlatch", generic_latch_8_device, read)
|
||||
// TODO: wrong for this
|
||||
AM_RANGE(0x8000, 0x803f) AM_DEVWRITE("wiping1", wiping_sound_device, sound_w)
|
||||
AM_RANGE(0xa000, 0xa03f) AM_DEVWRITE("wiping2", wiping_sound_device, sound_w)
|
||||
AM_RANGE(0x8000, 0x803f) AM_DEVWRITE("flower", flower_sound_device, lower_write)
|
||||
AM_RANGE(0xa000, 0xa03f) AM_DEVWRITE("flower", flower_sound_device, upper_write)
|
||||
AM_RANGE(0xc000, 0xc7ff) AM_RAM
|
||||
ADDRESS_MAP_END
|
||||
|
||||
@ -515,10 +514,7 @@ static MACHINE_CONFIG_START( flower )
|
||||
|
||||
MCFG_SPEAKER_STANDARD_MONO("mono")
|
||||
|
||||
MCFG_SOUND_ADD("wiping1", WIPING, 0)
|
||||
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
|
||||
|
||||
MCFG_SOUND_ADD("wiping2", WIPING, 0)
|
||||
MCFG_SOUND_ADD("flower", FLOWER_CUSTOM, 0)
|
||||
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
|
||||
MACHINE_CONFIG_END
|
||||
|
||||
@ -551,7 +547,7 @@ ROM_START( flower ) /* Komax version */
|
||||
ROM_REGION( 0x8000, "samples", 0 )
|
||||
ROM_LOAD( "4.12a", 0x0000, 0x8000, CRC(851ed9fd) SHA1(5dc048b612e45da529502bf33d968737a7b0a646) ) /* 8-bit samples */
|
||||
|
||||
ROM_REGION( 0x4000, "soundproms", 0 )
|
||||
ROM_REGION( 0x4000, "soundvol", 0 )
|
||||
ROM_LOAD( "5.16a", 0x0000, 0x4000, CRC(42fa2853) SHA1(cc1e8b8231d6f27f48b05d59390e93ea1c1c0e4c) ) /* volume tables? */
|
||||
|
||||
ROM_REGION( 0x300, "proms", 0 ) /* RGB proms */
|
||||
@ -594,7 +590,7 @@ ROM_START( flowerj ) /* Sega/Alpha version. Sega game number 834-5998 */
|
||||
ROM_REGION( 0x8000, "samples", 0 )
|
||||
ROM_LOAD( "4.12a", 0x0000, 0x8000, CRC(851ed9fd) SHA1(5dc048b612e45da529502bf33d968737a7b0a646) ) /* 8-bit samples */
|
||||
|
||||
ROM_REGION( 0x4000, "soundproms", 0 )
|
||||
ROM_REGION( 0x4000, "soundvol", 0 )
|
||||
ROM_LOAD( "5.16a", 0x0000, 0x4000, CRC(42fa2853) SHA1(cc1e8b8231d6f27f48b05d59390e93ea1c1c0e4c) ) /* volume tables? */
|
||||
|
||||
ROM_REGION( 0x300, "proms", 0 ) /* RGB proms */
|
||||
@ -610,5 +606,5 @@ ROM_START( flowerj ) /* Sega/Alpha version. Sega game number 834-5998 */
|
||||
ROM_END
|
||||
|
||||
|
||||
GAME( 1986, flower, 0, flower, flower, flower_state, 0, ROT0, "Clarue (Komax license)", "Flower (US)", MACHINE_NO_SOUND|MACHINE_IMPERFECT_GRAPHICS|MACHINE_NO_COCKTAIL )
|
||||
GAME( 1986, flowerj, flower, flower, flower, flower_state, 0, ROT0, "Clarue (Sega / Alpha Denshi Co. license)", "Flower (Japan)", MACHINE_NO_SOUND|MACHINE_IMPERFECT_GRAPHICS|MACHINE_NO_COCKTAIL )
|
||||
GAME( 1986, flower, 0, flower, flower, flower_state, 0, ROT0, "Clarue (Komax license)", "Flower (US)", MACHINE_IMPERFECT_SOUND|MACHINE_IMPERFECT_GRAPHICS|MACHINE_NO_COCKTAIL )
|
||||
GAME( 1986, flowerj, flower, flower, flower, flower_state, 0, ROT0, "Clarue (Sega / Alpha Denshi Co. license)", "Flower (Japan)", MACHINE_IMPERFECT_SOUND|MACHINE_IMPERFECT_GRAPHICS|MACHINE_NO_COCKTAIL )
|
||||
|
Loading…
Reference in New Issue
Block a user