summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/ymf271.h
blob: 39d51a64d05f7f4086ba5413be376fc5c933d0b4 (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
161
162
163
164
165
166
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont, hap
#pragma once

#ifndef __YMF271_H__
#define __YMF271_H__

#include "emu.h"

#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
{
public:
	ymf271_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);

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

	DECLARE_READ8_MEMBER( read );
	DECLARE_WRITE8_MEMBER( write );

protected:
	// device-level overrides
	virtual void device_config_complete() override;
	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;

	// sound stream update overrides
	virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
private:
	struct YMF271Slot
	{
		UINT8 ext_en;
		UINT8 ext_out;
		UINT8 lfoFreq;
		UINT8 lfowave;
		UINT8 pms, ams;
		UINT8 detune;
		UINT8 multiple;
		UINT8 tl;
		UINT8 keyscale;
		UINT8 ar;
		UINT8 decay1rate, decay2rate;
		UINT8 decay1lvl;
		UINT8 relrate;
		UINT8 block;
		UINT8 fns_hi;
		UINT32 fns;
		UINT8 feedback;
		UINT8 waveform;
		UINT8 accon;
		UINT8 algorithm;
		UINT8 ch0_level, ch1_level, ch2_level, ch3_level;

		UINT32 startaddr;
		UINT32 loopaddr;
		UINT32 endaddr;
		UINT8 altloop;
		UINT8 fs;
		UINT8 srcnote, srcb;

		UINT32 step;
		UINT64 stepptr;

		UINT8 active;
		UINT8 bits;

		// envelope generator
		INT32 volume;
		INT32 env_state;
		INT32 env_attack_step;      // volume increase step in attack state
		INT32 env_decay1_step;
		INT32 env_decay2_step;
		INT32 env_release_step;

		INT64 feedback_modulation0;
		INT64 feedback_modulation1;

		int lfo_phase, lfo_step;
		int lfo_amplitude;
		double lfo_phasemod;
	};

	struct YMF271Group
	{
		UINT8 sync, pfm;
	};

	void init_state();
	void init_tables();
	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 calculate_slot_volume(YMF271Slot *slot);
	void update_pcm(int slotnum, INT32 *mixp, int length);
	INT64 calculate_op(int slotnum, INT64 inp);
	void set_feedback(int slotnum, INT64 inp);
	void write_register(int slotnum, int reg, UINT8 data);
	void ymf271_write_fm(int bank, UINT8 address, UINT8 data);
	void ymf271_write_pcm(UINT8 address, UINT8 data);
	void ymf271_write_timer(UINT8 address, UINT8 data);
	UINT8 ymf271_read_memory(UINT32 offset);

	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);

	// lookup tables
	std::unique_ptr<INT16[]> 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 m_regs_main[0x10];

	UINT32 m_timerA;
	UINT32 m_timerB;
	UINT8 m_irqstate;
	UINT8 m_status;
	UINT8 m_enable;

	UINT32 m_ext_address;
	UINT8 m_ext_rw;
	UINT8 m_ext_readlatch;

	optional_region_ptr<UINT8> m_mem_base;
	UINT32 m_mem_size;
	UINT32 m_clock;

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

	devcb_write_line m_irq_handler;
	devcb_read8 m_ext_read_handler;
	devcb_write8 m_ext_write_handler;
};

extern const device_type YMF271;


#endif /* __YMF271_H__ */