diff options
Diffstat (limited to 'src/devices/sound/ymf271.cpp')
-rw-r--r-- | src/devices/sound/ymf271.cpp | 249 |
1 files changed, 114 insertions, 135 deletions
diff --git a/src/devices/sound/ymf271.cpp b/src/devices/sound/ymf271.cpp index 6b05f390275..aaa11319381 100644 --- a/src/devices/sound/ymf271.cpp +++ b/src/devices/sound/ymf271.cpp @@ -12,13 +12,13 @@ - EN and EXT Out bits - Src B and Src NOTE bits - statusreg Busy flag - - timer register 0x11 - 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 "determines if slot output is accumulated(1), or output directly(0)" - - Is memory handling 100% correct? At the moment, seibuspi.c is the only + - Is memory handling 100% correct? At the moment, seibuspi.cpp is the only hardware currently emulated that uses external handlers. + - *16 multiplier for timer B is free-running like other yamaha FM chips? */ #include "emu.h" @@ -253,11 +253,11 @@ inline void ymf271_device::calculate_status_end(int slotnum, bool state) if(slotnum & 3) return; - /* - bit scheme is kinda twisted - status1 Busy End36 End24 End12 End0 ---- TimB TimA - status2 End44 End32 End20 End8 End40 End28 End16 End4 - */ + /* + bit scheme is kinda twisted + status1 Busy End36 End24 End12 End0 ---- TimB TimA + status2 End44 End32 End20 End8 End40 End28 End16 End4 + */ uint8_t subbit = slotnum / 12; uint8_t bankbit = ((slotnum % 12) >> 2); @@ -402,7 +402,7 @@ void ymf271_device::init_envelope(YMF271Slot *slot) // init release state rate = get_keyscaled_rate(slot->relrate * 4, keycode, slot->keyscale); - slot->env_release_step = (rate < 4) ? 0 : (int)(((double)(255-0) / m_lut_ar[rate]) * 65536.0); + slot->env_release_step = (rate < 4) ? 0 : (int)(((double)(255-0) / m_lut_dc[rate]) * 65536.0); slot->volume = (255-160) << ENV_VOLUME_SHIFT; // -60db slot->env_state = ENV_ATTACK; @@ -566,7 +566,7 @@ void ymf271_device::set_feedback(int slotnum, int64_t inp) // sound_stream_update - handle a stream update //------------------------------------------------- -void ymf271_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +void ymf271_device::sound_stream_update(sound_stream &stream) { int i, j; int op; @@ -599,7 +599,7 @@ void ymf271_device::sound_stream_update(sound_stream &stream, stream_sample_t ** if (m_slots[slot1].active) { - for (i = 0; i < samples; i++) + for (i = 0; i < stream.samples(); i++) { int64_t output1 = 0, output2 = 0, output3 = 0, output4 = 0; int64_t phase_mod1, phase_mod2, phase_mod3; @@ -833,7 +833,7 @@ void ymf271_device::sound_stream_update(sound_stream &stream, stream_sample_t ** mixp = &m_mix_buffer[0]; if (m_slots[slot1].active) { - for (i = 0; i < samples; i++) + for (i = 0; i < stream.samples(); i++) { int64_t output1 = 0, output3 = 0; int64_t phase_mod1, phase_mod3; @@ -900,7 +900,7 @@ void ymf271_device::sound_stream_update(sound_stream &stream, stream_sample_t ** if (m_slots[slot1].active) { - for (i = 0; i < samples; i++) + for (i = 0; i < stream.samples(); i++) { int64_t output1 = 0, output2 = 0, output3 = 0; int64_t phase_mod1, phase_mod3; @@ -1006,29 +1006,29 @@ void ymf271_device::sound_stream_update(sound_stream &stream, stream_sample_t ** } mixp = &m_mix_buffer[0]; - update_pcm(j + (3*12), mixp, samples); + update_pcm(j + (3*12), mixp, stream.samples()); break; } // PCM case 3: { - update_pcm(j + (0*12), mixp, samples); - update_pcm(j + (1*12), mixp, samples); - update_pcm(j + (2*12), mixp, samples); - update_pcm(j + (3*12), mixp, samples); + update_pcm(j + (0*12), mixp, stream.samples()); + update_pcm(j + (1*12), mixp, stream.samples()); + update_pcm(j + (2*12), mixp, stream.samples()); + update_pcm(j + (3*12), mixp, stream.samples()); break; } } } mixp = &m_mix_buffer[0]; - for (i = 0; i < samples; i++) + for (i = 0; i < stream.samples(); i++) { - outputs[0][i] = (*mixp++)>>2; - outputs[1][i] = (*mixp++)>>2; - outputs[2][i] = (*mixp++)>>2; - outputs[3][i] = (*mixp++)>>2; + stream.put_int(0, i, *mixp++, 32768 << 2); + stream.put_int(1, i, *mixp++, 32768 << 2); + stream.put_int(2, i, *mixp++, 32768 << 2); + stream.put_int(3, i, *mixp++, 32768 << 2); } } @@ -1309,46 +1309,34 @@ void ymf271_device::ymf271_write_pcm(uint8_t address, uint8_t data) } } -void ymf271_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +TIMER_CALLBACK_MEMBER(ymf271_device::timer_a_expired) { - switch(id) - { - case 0: - m_status |= 1; - - // assert IRQ - if (m_enable & 4) - { - m_irqstate |= 1; - - if (!m_irq_handler.isnull()) - m_irq_handler(1); - } - - // reload timer - m_timA->adjust(clocks_to_attotime(384 * 4 * (256 - m_timerA)), 0); - break; + m_status |= 1; - case 1: - m_status |= 2; - - // assert IRQ - if (m_enable & 8) - { - m_irqstate |= 2; + // assert IRQ + if (m_enable & 4) + { + m_irqstate |= 1; + m_irq_handler(1); + } - if (!m_irq_handler.isnull()) - m_irq_handler(1); - } + // reload timer + m_timA->adjust(clocks_to_attotime(384 * (1024 - m_timerA)), 0); +} - // reload timer - m_timB->adjust(clocks_to_attotime(384 * 16 * (256 - m_timerB)), 0); - break; +TIMER_CALLBACK_MEMBER(ymf271_device::timer_b_expired) +{ + m_status |= 2; - default: - throw emu_fatalerror("Unknown id in ymf271_device::device_timer"); - break; + // assert IRQ + if (m_enable & 8) + { + m_irqstate |= 2; + m_irq_handler(1); } + + // reload timer + m_timB->adjust(clocks_to_attotime(384 * 16 * (256 - m_timerB)), 0); } void ymf271_device::ymf271_write_timer(uint8_t address, uint8_t data) @@ -1371,14 +1359,13 @@ void ymf271_device::ymf271_write_timer(uint8_t address, uint8_t data) switch (address) { case 0x10: - m_timerA = data; + m_timerA = (m_timerA & 0x003) | (data << 2); // High 8 bit of Timer A period break; case 0x11: - // According to Yamaha's documentation, this sets timer A upper 2 bits - // (it says timer A is 10 bits). But, PCB audio recordings proves - // otherwise: it doesn't affect timer A frequency. (see ms32.c tetrisp) - // Does this register have another function regarding timer A/B? + // Timer A is 10 bit, split high 8 bit and low 2 bit like other Yamaha FM chips + // unlike Yamaha's documentation; it says 0x11 writes timer A upper 2 bits. + m_timerA = (m_timerA & 0x3fc) | (data & 0x03); // Low 2 bit of Timer A period break; case 0x12: @@ -1389,7 +1376,7 @@ void ymf271_device::ymf271_write_timer(uint8_t address, uint8_t data) // timer A load if (~m_enable & data & 1) { - attotime period = clocks_to_attotime(384 * 4 * (256 - m_timerA)); + attotime period = clocks_to_attotime(384 * (1024 - m_timerA)); m_timA->adjust((data & 1) ? period : attotime::never, 0); } @@ -1406,7 +1393,7 @@ void ymf271_device::ymf271_write_timer(uint8_t address, uint8_t data) m_irqstate &= ~1; m_status &= ~1; - if (!m_irq_handler.isnull() && ~m_irqstate & 2) + if (~m_irqstate & 2) m_irq_handler(0); } @@ -1416,7 +1403,7 @@ void ymf271_device::ymf271_write_timer(uint8_t address, uint8_t data) m_irqstate &= ~2; m_status &= ~2; - if (!m_irq_handler.isnull() && ~m_irqstate & 1) + if (~m_irqstate & 1) m_irq_handler(0); } @@ -1520,8 +1507,11 @@ u8 ymf271_device::read(offs_t offset) return 0xff; uint8_t ret = m_ext_readlatch; - m_ext_address = (m_ext_address + 1) & 0x7fffff; - m_ext_readlatch = read_byte(m_ext_address); + if (!machine().side_effects_disabled()) + { + m_ext_address = (m_ext_address + 1) & 0x7fffff; + m_ext_readlatch = read_byte(m_ext_address); + } return ret; } @@ -1648,76 +1638,68 @@ void ymf271_device::calculate_clock_correction() for (int i = 0; i < 64; i++) { - // attack/release rate in number of samples + // attack rate in number of samples m_lut_ar[i] = (ARTime[i] * clock_correction * 44100.0) / 1000.0; } for (int i = 0; i < 64; i++) { - // decay rate in number of samples + // decay/release rate in number of samples m_lut_dc[i] = (DCTime[i] * clock_correction * 44100.0) / 1000.0; } } void ymf271_device::init_state() { - int i; - - for (i = 0; i < ARRAY_LENGTH(m_slots); i++) - { - save_item(NAME(m_slots[i].ext_en), i); - save_item(NAME(m_slots[i].ext_out), i); - save_item(NAME(m_slots[i].lfoFreq), i); - save_item(NAME(m_slots[i].pms), i); - save_item(NAME(m_slots[i].ams), i); - save_item(NAME(m_slots[i].detune), i); - save_item(NAME(m_slots[i].multiple), i); - save_item(NAME(m_slots[i].tl), i); - save_item(NAME(m_slots[i].keyscale), i); - save_item(NAME(m_slots[i].ar), i); - save_item(NAME(m_slots[i].decay1rate), i); - save_item(NAME(m_slots[i].decay2rate), i); - save_item(NAME(m_slots[i].decay1lvl), i); - save_item(NAME(m_slots[i].relrate), i); - save_item(NAME(m_slots[i].block), i); - save_item(NAME(m_slots[i].fns_hi), i); - save_item(NAME(m_slots[i].fns), i); - save_item(NAME(m_slots[i].feedback), i); - save_item(NAME(m_slots[i].waveform), i); - save_item(NAME(m_slots[i].accon), i); - save_item(NAME(m_slots[i].algorithm), i); - save_item(NAME(m_slots[i].ch0_level), i); - save_item(NAME(m_slots[i].ch1_level), i); - save_item(NAME(m_slots[i].ch2_level), i); - save_item(NAME(m_slots[i].ch3_level), i); - save_item(NAME(m_slots[i].startaddr), i); - save_item(NAME(m_slots[i].loopaddr), i); - save_item(NAME(m_slots[i].endaddr), i); - save_item(NAME(m_slots[i].altloop), i); - save_item(NAME(m_slots[i].fs), i); - save_item(NAME(m_slots[i].srcnote), i); - save_item(NAME(m_slots[i].srcb), i); - save_item(NAME(m_slots[i].step), i); - save_item(NAME(m_slots[i].stepptr), i); - save_item(NAME(m_slots[i].active), i); - save_item(NAME(m_slots[i].bits), i); - save_item(NAME(m_slots[i].volume), i); - save_item(NAME(m_slots[i].env_state), i); - save_item(NAME(m_slots[i].env_attack_step), i); - save_item(NAME(m_slots[i].env_decay1_step), i); - save_item(NAME(m_slots[i].env_decay2_step), i); - save_item(NAME(m_slots[i].env_release_step), i); - save_item(NAME(m_slots[i].feedback_modulation0), i); - save_item(NAME(m_slots[i].feedback_modulation1), i); - save_item(NAME(m_slots[i].lfo_phase), i); - save_item(NAME(m_slots[i].lfo_step), i); - save_item(NAME(m_slots[i].lfo_amplitude), i); - } - - for (i = 0; i < ARRAY_LENGTH(m_groups); i++) - { - save_item(NAME(m_groups[i].sync), i); - save_item(NAME(m_groups[i].pfm), i); - } + save_item(STRUCT_MEMBER(m_slots, ext_en)); + save_item(STRUCT_MEMBER(m_slots, ext_out)); + save_item(STRUCT_MEMBER(m_slots, lfoFreq)); + save_item(STRUCT_MEMBER(m_slots, pms)); + save_item(STRUCT_MEMBER(m_slots, ams)); + save_item(STRUCT_MEMBER(m_slots, detune)); + save_item(STRUCT_MEMBER(m_slots, multiple)); + save_item(STRUCT_MEMBER(m_slots, tl)); + save_item(STRUCT_MEMBER(m_slots, keyscale)); + save_item(STRUCT_MEMBER(m_slots, ar)); + save_item(STRUCT_MEMBER(m_slots, decay1rate)); + save_item(STRUCT_MEMBER(m_slots, decay2rate)); + save_item(STRUCT_MEMBER(m_slots, decay1lvl)); + save_item(STRUCT_MEMBER(m_slots, relrate)); + save_item(STRUCT_MEMBER(m_slots, block)); + save_item(STRUCT_MEMBER(m_slots, fns_hi)); + save_item(STRUCT_MEMBER(m_slots, fns)); + save_item(STRUCT_MEMBER(m_slots, feedback)); + save_item(STRUCT_MEMBER(m_slots, waveform)); + save_item(STRUCT_MEMBER(m_slots, accon)); + save_item(STRUCT_MEMBER(m_slots, algorithm)); + save_item(STRUCT_MEMBER(m_slots, ch0_level)); + save_item(STRUCT_MEMBER(m_slots, ch1_level)); + save_item(STRUCT_MEMBER(m_slots, ch2_level)); + save_item(STRUCT_MEMBER(m_slots, ch3_level)); + save_item(STRUCT_MEMBER(m_slots, startaddr)); + save_item(STRUCT_MEMBER(m_slots, loopaddr)); + save_item(STRUCT_MEMBER(m_slots, endaddr)); + save_item(STRUCT_MEMBER(m_slots, altloop)); + save_item(STRUCT_MEMBER(m_slots, fs)); + save_item(STRUCT_MEMBER(m_slots, srcnote)); + save_item(STRUCT_MEMBER(m_slots, srcb)); + save_item(STRUCT_MEMBER(m_slots, step)); + save_item(STRUCT_MEMBER(m_slots, stepptr)); + save_item(STRUCT_MEMBER(m_slots, active)); + save_item(STRUCT_MEMBER(m_slots, bits)); + save_item(STRUCT_MEMBER(m_slots, volume)); + save_item(STRUCT_MEMBER(m_slots, env_state)); + save_item(STRUCT_MEMBER(m_slots, env_attack_step)); + save_item(STRUCT_MEMBER(m_slots, env_decay1_step)); + save_item(STRUCT_MEMBER(m_slots, env_decay2_step)); + save_item(STRUCT_MEMBER(m_slots, env_release_step)); + save_item(STRUCT_MEMBER(m_slots, feedback_modulation0)); + save_item(STRUCT_MEMBER(m_slots, feedback_modulation1)); + save_item(STRUCT_MEMBER(m_slots, lfo_phase)); + save_item(STRUCT_MEMBER(m_slots, lfo_step)); + save_item(STRUCT_MEMBER(m_slots, lfo_amplitude)); + + save_item(STRUCT_MEMBER(m_groups, sync)); + save_item(STRUCT_MEMBER(m_groups, pfm)); save_item(NAME(m_regs_main)); save_item(NAME(m_timerA)); @@ -1738,17 +1720,15 @@ void ymf271_device::init_state() void ymf271_device::device_start() { - m_timA = timer_alloc(0); - m_timB = timer_alloc(1); - - m_irq_handler.resolve(); + m_timA = timer_alloc(FUNC(ymf271_device::timer_a_expired), this); + m_timB = timer_alloc(FUNC(ymf271_device::timer_b_expired), this); m_master_clock = clock(); init_tables(); init_state(); m_mix_buffer.resize(m_master_clock/(384/4)); - m_stream = machine().sound().stream_alloc(*this, 0, 4, m_master_clock/384); + m_stream = stream_alloc(0, 4, m_master_clock/384); } //------------------------------------------------- @@ -1771,8 +1751,7 @@ void ymf271_device::device_reset() m_status = 0; m_enable = 0; - if (!m_irq_handler.isnull()) - m_irq_handler(0); + m_irq_handler(0); } //------------------------------------------------- @@ -1795,7 +1774,7 @@ void ymf271_device::device_clock_changed() calculate_clock_correction(); } -void ymf271_device::rom_bank_updated() +void ymf271_device::rom_bank_pre_change() { m_stream->update(); } @@ -1805,7 +1784,7 @@ 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) + , device_rom_interface(mconfig, *this) , m_timerA(0) , m_timerB(0) , m_irqstate(0) |