summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/sound/ym3526.cpp
blob: 14e325392d1281165ed5e630441635583b48167a (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
// license:BSD-3-Clause
// copyright-holders:Aaron Giles

#include "emu.h"
#include "ym3526.h"


DEFINE_DEVICE_TYPE(YM3526, ym3526_device, "ym3526", "YM3526 OPL")


//*********************************************************
//  YM3526 DEVICE
//*********************************************************

//-------------------------------------------------
//  ym3526_device - constructor
//-------------------------------------------------

ym3526_device::ym3526_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, device_type type) :
	device_t(mconfig, type, tag, owner, clock),
	device_sound_interface(mconfig, *this),
	m_address(0),
	m_stream(nullptr),
	m_fm(*this)
{
}


//-------------------------------------------------
//  status_r - return the status port (A0=0)
//-------------------------------------------------

u8 ym3526_device::status_r()
{
	return m_fm.status() | 0x06;
}


//-------------------------------------------------
//  read - handle a read from the device
//-------------------------------------------------

u8 ym3526_device::read(offs_t offset)
{
	// datasheet says status only reads when A0=0
	if ((offset & 1) == 0)
		return status_r();

	// when A0=1 datasheet says "the data on the bus are not guaranteed"
	logerror("Unexpected read from YM3526 offset %d\n", offset & 1);
	return 0xff;
}


//-------------------------------------------------
//  address_w - write to the address port (A0=0)
//-------------------------------------------------

void ym3526_device::address_w(u8 value)
{
	m_address = value;
}


//-------------------------------------------------
//  data_w - write to the data port (A0=1)
//-------------------------------------------------

void ym3526_device::data_w(u8 value)
{
	// force an update
	m_stream->update();

	// write to FM
	m_fm.write(m_address, value);
}


//-------------------------------------------------
//  write - handle a write to the register
//  interface
//-------------------------------------------------

void ym3526_device::write(offs_t offset, u8 value)
{
	// A0 selects between address/data
	if ((offset & 1) == 0)
		address_w(value);
	else
		data_w(value);
}


//-------------------------------------------------
//  device_start - start of emulation
//-------------------------------------------------

void ym3526_device::device_start()
{
	// create our stream
	m_stream = stream_alloc(0, fm_engine::OUTPUTS, m_fm.sample_rate(clock()));

	// initialize the FM engine
	m_fm.init();
}


//-------------------------------------------------
//  device_register_save - register for save state
//-------------------------------------------------

void ym3526_device::device_register_save(save_registrar &save)
{
	// save our data
	save.reg(NAME(m_address))
		.reg(NAME(m_fm));
}


//-------------------------------------------------
//  device_reset - start of emulation
//-------------------------------------------------

void ym3526_device::device_reset()
{
	// reset the engines
	m_fm.reset();
}


//-------------------------------------------------
//  device_clock_changed - update if clock changes
//-------------------------------------------------

void ym3526_device::device_clock_changed()
{
	m_stream->set_sample_rate(m_fm.sample_rate(clock()));
}


//-------------------------------------------------
//  sound_stream_update - update the sound stream
//-------------------------------------------------

void ym3526_device::sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs)
{
	// iterate over all target samples
	for (int sampindex = 0; sampindex < outputs[0].samples(); sampindex++)
	{
		// clock the system
		m_fm.clock(fm_engine::ALL_CHANNELS);

		// update the FM content; clipping is unknown
		s32 sums[fm_engine::OUTPUTS] = { 0 };
		m_fm.output(sums, 1, 32767, fm_engine::ALL_CHANNELS);

		// convert to 10.3 floating point value for the DAC and back
		// YM3526 is mono
		for (int index = 0; index < fm_engine::OUTPUTS; index++)
			outputs[index].put_int(sampindex, ymfm_roundtrip_fp(sums[index]), 32768);
	}
}