summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/ymf271.h
blob: 075650b85862b3a81d72b0dbeff6c0790cc0bf52 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// 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) \
	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