looper/backends/playback/zsm/x16emu/ymglue.cpp

143 lines
3 KiB
C++
Raw Normal View History

2024-08-08 13:12:37 -07:00
#include "ymglue.h"
#include "ymfm_opm.h"
#include <cstdint>
class ym2151_interface : public ymfm::ymfm_interface {
public:
ym2151_interface():
m_chip(*this),
m_timers{0, 0},
m_busy_timer{ 0 },
m_irq_status{ false }
{ }
~ym2151_interface() { }
virtual void ymfm_sync_mode_write(uint8_t data) override {
m_engine->engine_mode_write(data);
}
virtual void ymfm_sync_check_interrupts() override {
m_engine->engine_check_interrupts();
}
virtual void ymfm_set_timer(uint32_t tnum, int32_t duration_in_clocks) override {
if (tnum >= 2) return;
m_timers[tnum] = duration_in_clocks;
}
virtual void ymfm_set_busy_end(uint32_t clocks) override {
m_busy_timer = clocks;
}
virtual bool ymfm_is_busy() override {
return m_busy_timer > 0;
}
virtual void ymfm_update_irq(bool asserted) override {
m_irq_status = asserted;
}
void update_clocks(int cycles) {
m_busy_timer = std::max(0, m_busy_timer - (64 * cycles));
for (int i = 0; i < 2; ++i) {
if (m_timers[i] > 0) {
m_timers[i] = std::max(0, m_timers[i] - (64 * cycles));
if (m_timers[i] <= 0) {
m_engine->engine_timer_expired(i);
}
}
}
}
void write(uint8_t addr, uint8_t value) {
if (!ymfm_is_busy()) {
m_chip.write_address(addr);
m_chip.write_data(value);
} else {
printf("YM2151 write received while busy.\n");
}
}
void generate(int16_t* output, uint32_t numsamples) {
int s = 0;
int ls, rs;
update_clocks(numsamples);
for (uint32_t i = 0; i < numsamples; i++) {
m_chip.generate(&opm_out);
ls = opm_out.data[0];
rs = opm_out.data[1];
if (ls < -32768) ls = -32768;
if (ls > 32767) ls = 32767;
if (rs < -32768) rs = -32768;
if (rs > 32767) rs = 32767;
output[s++] = ls;
output[s++] = rs;
}
}
uint8_t read_status() {
return m_chip.read_status();
}
bool irq() {
return m_irq_status;
}
void reset() {
m_chip.reset();
m_timers[0] = 0;
m_timers[1] = 0;
m_busy_timer = 0;
m_irq_status = false;
opm_out.clear();
}
2024-08-08 13:12:37 -07:00
private:
ymfm::ym2151 m_chip;
int32_t m_timers[2];
int32_t m_busy_timer;
bool m_irq_status;
ymfm::ym2151::output_data opm_out;
};
namespace {
ym2151_interface opm_iface;
bool initialized = false;
}
extern "C" {
void YM_Create(int clock) {
// clock is fixed at 3.579545MHz
}
void YM_init(int sample_rate, int frame_rate) {
// args are ignored
initialized = true;
}
2024-10-14 21:27:16 -07:00
void YM_stream_update(int16_t* output, uint32_t numsamples) {
if (initialized) opm_iface.generate(output, numsamples);
2024-08-08 13:12:37 -07:00
}
void YM_write_reg(uint8_t reg, uint8_t val) {
if (initialized) opm_iface.write(reg, val);
}
void YM_reset() {
opm_iface.reset();
}
2024-08-08 13:12:37 -07:00
uint8_t YM_read_status() {
if (initialized)
return opm_iface.read_status();
else
return 0x00; // prevent programs that wait for the busy flag to clear from locking up (emulator compromise)
}
bool YM_irq() {
if (initialized)
return opm_iface.irq();
else
return false;
}
}