Skip to content

Commit

Permalink
Allow YMF271 4 Channel Output, Move Imperfect_sound tags into ymf271.h (
Browse files Browse the repository at this point in the history
#3229)

* ymf271 : Allow 4 channel output, Add notes, Convert external memory handler to address space, Add notes, Move global imperfect_sound tags to device imperfect_features
ms32, bnstars, seibuspi : Minor bankswitching cleanup, Add notes
ms32 : Real mobo can output stereo sound (ex: http: //www.nicovideo.jp/watch/sm23743949) And mobo has a second stereo sound connector, Accurate this
seibuspi : Single PCBs only output mono sound(sxx2e PCB : unverified), Accurate this

* seibuspi : Fix unneeded

* seibuspi.h : REAL remove unneeded

* seibuspi.cpp : Remove duplicates

* seibuspi.h : Minor cleanup
  • Loading branch information
cam900 authored and cuavas committed Feb 22, 2018
1 parent 638f84f commit 4457a26
Show file tree
Hide file tree
Showing 8 changed files with 238 additions and 236 deletions.
116 changes: 66 additions & 50 deletions src/devices/sound/ymf271.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
- Src B and Src NOTE bits
- statusreg Busy flag
- timer register 0x11
- ch2/ch3 (4 speakers)
- PFM (FM using external PCM waveform)
- detune (should be same as on other Yamaha chips)
- Acc On bit (some sound effects in viprp1?). The documentation says
Expand All @@ -25,6 +24,8 @@
#include "emu.h"
#include "ymf271.h"

#include <algorithm>

#define STD_CLOCK (16934400)

#define MAXOUT (+32767)
Expand Down Expand Up @@ -452,7 +453,7 @@ void ymf271_device::update_pcm(int slotnum, int32_t *mixp, int length)
int i;
int64_t final_volume;
int16_t sample;
int64_t ch0_vol, ch1_vol; //, ch2_vol, ch3_vol;
int64_t ch0_vol, ch1_vol, ch2_vol, ch3_vol;

YMF271Slot *slot = &m_slots[slotnum];

Expand Down Expand Up @@ -490,15 +491,15 @@ void ymf271_device::update_pcm(int slotnum, int32_t *mixp, int length)
if (slot->bits == 8)
{
// 8bit
sample = ymf271_read_memory(slot->startaddr + (slot->stepptr>>16))<<8;
sample = read_byte(slot->startaddr + (slot->stepptr>>16))<<8;
}
else
{
// 12bit
if (slot->stepptr & 0x10000)
sample = ymf271_read_memory(slot->startaddr + (slot->stepptr>>17)*3 + 2)<<8 | ((ymf271_read_memory(slot->startaddr + (slot->stepptr>>17)*3 + 1) << 4) & 0xf0);
sample = read_byte(slot->startaddr + (slot->stepptr>>17)*3 + 2)<<8 | ((read_byte(slot->startaddr + (slot->stepptr>>17)*3 + 1) << 4) & 0xf0);
else
sample = ymf271_read_memory(slot->startaddr + (slot->stepptr>>17)*3)<<8 | (ymf271_read_memory(slot->startaddr + (slot->stepptr>>17)*3 + 1) & 0xf0);
sample = read_byte(slot->startaddr + (slot->stepptr>>17)*3)<<8 | (read_byte(slot->startaddr + (slot->stepptr>>17)*3 + 1) & 0xf0);
}

update_envelope(slot);
Expand All @@ -508,14 +509,18 @@ void ymf271_device::update_pcm(int slotnum, int32_t *mixp, int length)

ch0_vol = (final_volume * m_lut_attenuation[slot->ch0_level]) >> 16;
ch1_vol = (final_volume * m_lut_attenuation[slot->ch1_level]) >> 16;
// ch2_vol = (final_volume * m_lut_attenuation[slot->ch2_level]) >> 16;
// ch3_vol = (final_volume * m_lut_attenuation[slot->ch3_level]) >> 16;
ch2_vol = (final_volume * m_lut_attenuation[slot->ch2_level]) >> 16;
ch3_vol = (final_volume * m_lut_attenuation[slot->ch3_level]) >> 16;

if (ch0_vol > 65536) ch0_vol = 65536;
if (ch1_vol > 65536) ch1_vol = 65536;

if (ch2_vol > 65536) ch2_vol = 65536;
if (ch3_vol > 65536) ch3_vol = 65536;

*mixp++ += (sample * ch0_vol) >> 16;
*mixp++ += (sample * ch1_vol) >> 16;
*mixp++ += (sample * ch2_vol) >> 16;
*mixp++ += (sample * ch3_vol) >> 16;

// go to next step
slot->stepptr += slot->step;
Expand Down Expand Up @@ -567,12 +572,12 @@ void ymf271_device::sound_stream_update(sound_stream &stream, stream_sample_t **
int op;
int32_t *mixp;

memset(m_mix_buffer.get(), 0, sizeof(m_mix_buffer[0])*samples*2);
std::fill(m_mix_buffer.begin(), m_mix_buffer.end(), 0);

for (j = 0; j < 12; j++)
{
YMF271Group *slot_group = &m_groups[j];
mixp = m_mix_buffer.get();
mixp = &m_mix_buffer[0];

if (slot_group->pfm && slot_group->sync != 3)
{
Expand All @@ -590,7 +595,7 @@ void ymf271_device::sound_stream_update(sound_stream &stream, stream_sample_t **
int slot2 = j + (1*12);
int slot3 = j + (2*12);
int slot4 = j + (3*12);
mixp = m_mix_buffer.get();
mixp = &m_mix_buffer[0];

if (m_slots[slot1].active)
{
Expand Down Expand Up @@ -804,6 +809,14 @@ void ymf271_device::sound_stream_update(sound_stream &stream, stream_sample_t **
(output2 * m_lut_attenuation[m_slots[slot2].ch1_level]) +
(output3 * m_lut_attenuation[m_slots[slot3].ch1_level]) +
(output4 * m_lut_attenuation[m_slots[slot4].ch1_level])) >> 16;
*mixp++ += ((output1 * m_lut_attenuation[m_slots[slot1].ch2_level]) +
(output2 * m_lut_attenuation[m_slots[slot2].ch2_level]) +
(output3 * m_lut_attenuation[m_slots[slot3].ch2_level]) +
(output4 * m_lut_attenuation[m_slots[slot4].ch2_level])) >> 16;
*mixp++ += ((output1 * m_lut_attenuation[m_slots[slot1].ch3_level]) +
(output2 * m_lut_attenuation[m_slots[slot2].ch3_level]) +
(output3 * m_lut_attenuation[m_slots[slot3].ch3_level]) +
(output4 * m_lut_attenuation[m_slots[slot4].ch3_level])) >> 16;
}
}
break;
Expand All @@ -817,7 +830,7 @@ void ymf271_device::sound_stream_update(sound_stream &stream, stream_sample_t **
int slot1 = j + ((op + 0) * 12);
int slot3 = j + ((op + 2) * 12);

mixp = m_mix_buffer.get();
mixp = &m_mix_buffer[0];
if (m_slots[slot1].active)
{
for (i = 0; i < samples; i++)
Expand Down Expand Up @@ -867,6 +880,10 @@ void ymf271_device::sound_stream_update(sound_stream &stream, stream_sample_t **
(output3 * m_lut_attenuation[m_slots[slot3].ch0_level])) >> 16;
*mixp++ += ((output1 * m_lut_attenuation[m_slots[slot1].ch1_level]) +
(output3 * m_lut_attenuation[m_slots[slot3].ch1_level])) >> 16;
*mixp++ += ((output1 * m_lut_attenuation[m_slots[slot1].ch2_level]) +
(output3 * m_lut_attenuation[m_slots[slot3].ch2_level])) >> 16;
*mixp++ += ((output1 * m_lut_attenuation[m_slots[slot1].ch3_level]) +
(output3 * m_lut_attenuation[m_slots[slot3].ch3_level])) >> 16;
}
}
}
Expand All @@ -879,7 +896,7 @@ void ymf271_device::sound_stream_update(sound_stream &stream, stream_sample_t **
int slot1 = j + (0*12);
int slot2 = j + (1*12);
int slot3 = j + (2*12);
mixp = m_mix_buffer.get();
mixp = &m_mix_buffer[0];

if (m_slots[slot1].active)
{
Expand Down Expand Up @@ -979,10 +996,16 @@ void ymf271_device::sound_stream_update(sound_stream &stream, stream_sample_t **
*mixp++ += ((output1 * m_lut_attenuation[m_slots[slot1].ch1_level]) +
(output2 * m_lut_attenuation[m_slots[slot2].ch1_level]) +
(output3 * m_lut_attenuation[m_slots[slot3].ch1_level])) >> 16;
*mixp++ += ((output1 * m_lut_attenuation[m_slots[slot1].ch2_level]) +
(output2 * m_lut_attenuation[m_slots[slot2].ch2_level]) +
(output3 * m_lut_attenuation[m_slots[slot3].ch2_level])) >> 16;
*mixp++ += ((output1 * m_lut_attenuation[m_slots[slot1].ch3_level]) +
(output2 * m_lut_attenuation[m_slots[slot2].ch3_level]) +
(output3 * m_lut_attenuation[m_slots[slot3].ch3_level])) >> 16;
}
}

mixp = m_mix_buffer.get();
mixp = &m_mix_buffer[0];
update_pcm(j + (3*12), mixp, samples);
break;
}
Expand All @@ -999,11 +1022,13 @@ void ymf271_device::sound_stream_update(sound_stream &stream, stream_sample_t **
}
}

mixp = m_mix_buffer.get();
mixp = &m_mix_buffer[0];
for (i = 0; i < samples; i++)
{
outputs[0][i] = (*mixp++)>>2;
outputs[1][i] = (*mixp++)>>2;
outputs[2][i] = (*mixp++)>>2;
outputs[3][i] = (*mixp++)>>2;
}
}

Expand Down Expand Up @@ -1036,6 +1061,7 @@ void ymf271_device::write_register(int slotnum, int reg, uint8_t data)
{
if (slot->active)
{
//calculate_status_end(slotnum,true); status changes if keyoff? verify this from real hardware.
slot->env_state = ENV_RELEASE;
}
}
Expand Down Expand Up @@ -1325,24 +1351,6 @@ void ymf271_device::device_timer(emu_timer &timer, device_timer_id id, int param
}
}

uint8_t ymf271_device::ymf271_read_memory(uint32_t offset)
{
if (m_ext_read_handler.isnull())
{
if (offset < m_mem_size)
return m_mem_base[offset];

/* 8MB chip limit (shouldn't happen) */
else if (offset > 0x7fffff)
return ymf271_read_memory(offset & 0x7fffff);

else
return 0;
}
else
return m_ext_read_handler(offset);
}

void ymf271_device::ymf271_write_timer(uint8_t address, uint8_t data)
{
if ((address & 0xf0) == 0)
Expand Down Expand Up @@ -1433,8 +1441,8 @@ void ymf271_device::ymf271_write_timer(uint8_t address, uint8_t data)

case 0x17:
m_ext_address = (m_ext_address + 1) & 0x7fffff;
if (!m_ext_rw && !m_ext_write_handler.isnull())
m_ext_write_handler(m_ext_address, data);
if (!m_ext_rw)
space(0).write_byte(m_ext_address, data);
break;

case 0x20:
Expand Down Expand Up @@ -1513,7 +1521,7 @@ READ8_MEMBER( ymf271_device::read )

uint8_t ret = m_ext_readlatch;
m_ext_address = (m_ext_address + 1) & 0x7fffff;
m_ext_readlatch = ymf271_read_memory(m_ext_address);
m_ext_readlatch = read_byte(m_ext_address);
return ret;
}

Expand Down Expand Up @@ -1721,6 +1729,7 @@ void ymf271_device::init_state()
save_item(NAME(m_ext_address));
save_item(NAME(m_ext_rw));
save_item(NAME(m_ext_readlatch));
save_item(NAME(m_master_clock));
}

//-------------------------------------------------
Expand All @@ -1732,18 +1741,14 @@ void ymf271_device::device_start()
m_timA = timer_alloc(0);
m_timB = timer_alloc(1);

m_mem_size = m_mem_base.bytes();

m_irq_handler.resolve();

m_ext_read_handler.resolve();
m_ext_write_handler.resolve();

m_master_clock = clock();
init_tables();
init_state();

m_stream = machine().sound().stream_alloc(*this, 0, 2, clock()/384);
m_mix_buffer = std::make_unique<int32_t[]>(44100*2);
m_mix_buffer.resize(m_master_clock/(384/4));
m_stream = machine().sound().stream_alloc(*this, 0, 4, m_master_clock/384);
}

//-------------------------------------------------
Expand Down Expand Up @@ -1777,15 +1782,30 @@ void ymf271_device::device_reset()

void ymf271_device::device_clock_changed()
{
m_stream->set_sample_rate(clock() / 384);
uint32_t old_clock = m_master_clock;
m_master_clock = clock();

if (m_master_clock != old_clock)
{
if (old_clock < m_master_clock)
m_mix_buffer.resize(m_master_clock/(384/4));

m_stream->set_sample_rate(m_master_clock / 384);
}
calculate_clock_correction();
}

void ymf271_device::rom_bank_updated()
{
m_stream->update();
}

DEFINE_DEVICE_TYPE(YMF271, ymf271_device, "ymf271", "Yamaha YMF271 OPX")

ymf271_device::ymf271_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, YMF271, tag, owner, clock)
, device_sound_interface(mconfig, *this)
, device_rom_interface(mconfig, *this, 23)
, m_timerA(0)
, m_timerB(0)
, m_irqstate(0)
Expand All @@ -1794,15 +1814,11 @@ ymf271_device::ymf271_device(const machine_config &mconfig, const char *tag, dev
, m_ext_address(0)
, m_ext_rw(0)
, m_ext_readlatch(0)
, m_mem_base(*this, DEVICE_SELF)
, m_mem_size(0)
, m_master_clock(0)
, m_timA(nullptr)
, m_timB(nullptr)
, m_stream(nullptr)
, m_mix_buffer(nullptr)
, m_irq_handler(*this)
, m_ext_read_handler(*this)
, m_ext_write_handler(*this)
{
memset(m_slots, 0, sizeof(m_slots));
memset(m_groups, 0, sizeof(m_groups));
Expand Down
23 changes: 8 additions & 15 deletions src/devices/sound/ymf271.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,15 @@
#define MCFG_YMF271_IRQ_HANDLER(_devcb) \
devcb = &ymf271_device::set_irq_handler(*device, DEVCB_##_devcb);

#define MCFG_YMF271_EXT_READ_HANDLER(_devcb) \
devcb = &ymf271_device::set_ext_read_handler(*device, DEVCB_##_devcb);

#define MCFG_YMF271_EXT_WRITE_HANDLER(_devcb) \
devcb = &ymf271_device::set_ext_write_handler(*device, DEVCB_##_devcb);

class ymf271_device : public device_t, public device_sound_interface
class ymf271_device : public device_t, public device_sound_interface, public device_rom_interface
{
public:
static constexpr feature_type imperfect_features() { return feature::SOUND; }

ymf271_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

// static configuration helpers
template <class Object> static devcb_base &set_irq_handler(device_t &device, Object &&cb) { return downcast<ymf271_device &>(device).m_irq_handler.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_ext_read_handler(device_t &device, Object &&cb) { return downcast<ymf271_device &>(device).m_ext_read_handler.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_ext_write_handler(device_t &device, Object &&cb) { return downcast<ymf271_device &>(device).m_ext_write_handler.set_callback(std::forward<Object>(cb)); }

DECLARE_READ8_MEMBER( read );
DECLARE_WRITE8_MEMBER( write );
Expand All @@ -38,6 +32,9 @@ class ymf271_device : public device_t, public device_sound_interface
// sound stream update overrides
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;

// device_rom_interface overrides
virtual void rom_bank_updated() override;

private:
struct YMF271Slot
{
Expand Down Expand Up @@ -113,7 +110,6 @@ class ymf271_device : public device_t, public device_sound_interface
void ymf271_write_fm(int bank, uint8_t address, uint8_t data);
void ymf271_write_pcm(uint8_t address, uint8_t data);
void ymf271_write_timer(uint8_t address, uint8_t data);
uint8_t ymf271_read_memory(uint32_t offset);

inline int get_keyscaled_rate(int rate, int keycode, int keyscale);
inline int get_internal_keycode(int block, int fns);
Expand Down Expand Up @@ -149,17 +145,14 @@ class ymf271_device : public device_t, public device_sound_interface
uint8_t m_ext_rw;
uint8_t m_ext_readlatch;

optional_region_ptr<uint8_t> m_mem_base;
uint32_t m_mem_size;
uint32_t m_master_clock;

emu_timer *m_timA;
emu_timer *m_timB;
sound_stream *m_stream;
std::unique_ptr<int32_t[]> m_mix_buffer;
std::vector<int32_t> m_mix_buffer;

devcb_write_line m_irq_handler;
devcb_read8 m_ext_read_handler;
devcb_write8 m_ext_write_handler;
};

DECLARE_DEVICE_TYPE(YMF271, ymf271_device)
Expand Down
Loading

0 comments on commit 4457a26

Please sign in to comment.