// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont, hap
#ifndef MAME_SOUND_YMF271_H
#define MAME_SOUND_YMF271_H
#pragma once
#define MCFG_YMF271_IRQ_HANDLER(_devcb) \
devcb = &downcast<ymf271_device &>(*device).set_irq_handler(DEVCB_##_devcb);
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);
// configuration helpers
template <class Object> devcb_base &set_irq_handler(Object &&cb) { return m_irq_handler.set_callback(std::forward<Object>(cb)); }
DECLARE_READ8_MEMBER( read );
DECLARE_WRITE8_MEMBER( write );
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
virtual void device_clock_changed() override;
// 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
{
uint8_t ext_en;
uint8_t ext_out;
uint8_t lfoFreq;
uint8_t lfowave;
uint8_t pms, ams;
uint8_t detune;
uint8_t multiple;
uint8_t tl;
uint8_t keyscale;
uint8_t ar;
uint8_t decay1rate, decay2rate;
uint8_t decay1lvl;
uint8_t relrate;
uint8_t block;
uint8_t fns_hi;
uint32_t fns;
uint8_t feedback;
uint8_t waveform;
uint8_t accon;
uint8_t algorithm;
uint8_t ch0_level, ch1_level, ch2_level, ch3_level;
uint32_t startaddr;
uint32_t loopaddr;
uint32_t endaddr;
uint8_t altloop;
uint8_t fs;
uint8_t srcnote, srcb;
uint32_t step;
uint64_t stepptr;
uint8_t active;
uint8_t bits;
// envelope generator
int32_t volume;
int32_t env_state;
int32_t env_attack_step; // volume increase step in attack state
int32_t env_decay1_step;
int32_t env_decay2_step;
int32_t env_release_step;
int64_t feedback_modulation0;
int64_t feedback_modulation1;
int lfo_phase, lfo_step;
int lfo_amplitude;
double lfo_phasemod;
};
struct YMF271Group
{
uint8_t sync, pfm;
};
void init_state();
void init_tables();
void calculate_clock_correction();
void calculate_step(YMF271Slot *slot);
void update_envelope(YMF271Slot *slot);
void init_envelope(YMF271Slot *slot);
void init_lfo(YMF271Slot *slot);
void update_lfo(YMF271Slot *slot);
int64_t calculate_slot_volume(YMF271Slot *slot);
void update_pcm(int slotnum, int32_t *mixp, int length);
int64_t calculate_op(int slotnum, int64_t inp);
void set_feedback(int slotnum, int64_t inp);
void write_register(int slotnum, int reg, uint8_t data);
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);
inline int get_keyscaled_rate(int rate, int keycode, int keyscale);
inline int get_internal_keycode(int block, int fns);
inline int get_external_keycode(int block, int fns);
inline bool check_envelope_end(YMF271Slot *slot);
inline void calculate_status_end(int slotnum, bool state);
// lookup tables
std::unique_ptr<int16_t[]> m_lut_waves[8];
std::unique_ptr<double[]> m_lut_plfo[4][8];
std::unique_ptr<int[]> m_lut_alfo[4];
double m_lut_ar[64];
double m_lut_dc[64];
double m_lut_lfo[256];
int m_lut_attenuation[16];
int m_lut_total_level[128];
int m_lut_env_volume[256];
// internal state
YMF271Slot m_slots[48];
YMF271Group m_groups[12];
uint8_t m_regs_main[0x10];
uint32_t m_timerA;
uint32_t m_timerB;
uint8_t m_irqstate;
uint8_t m_status;
uint16_t m_end_status;
uint8_t m_enable;
uint32_t m_ext_address;
uint8_t m_ext_rw;
uint8_t m_ext_readlatch;
uint32_t m_master_clock;
emu_timer *m_timA;
emu_timer *m_timB;
sound_stream *m_stream;
std::vector<int32_t> m_mix_buffer;
devcb_write_line m_irq_handler;
};
DECLARE_DEVICE_TYPE(YMF271, ymf271_device)
#endif // MAME_SOUND_YMF271_H