OXYGENHUB
◆ main openmsx / src / sound / YM2413.cc
3.4 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#include "YM2413.hh"
2
3
#include "YM2413Burczynski.hh"
4
#include "YM2413NukeYKT.hh"
5
#include "YM2413Okazaki.hh"
6
#include "YM2413OriginalNukeYKT.hh"
7
8
#include "DeviceConfig.hh"
9
#include "MSXException.hh"
10
#include "serialize.hh"
11
12
#include "cstd.hh"
13
#include "narrow.hh"
14
#include "outer.hh"
15
16
#include <memory>
17
18
namespace openmsx {
19
20
// Debuggable
21
22
YM2413::Debuggable::Debuggable(
23
		MSXMotherBoard& motherBoard_, const std::string& name_)
24
	: SimpleDebuggable(motherBoard_, name_ + " regs", "MSX-MUSIC", 0x40)
25
{
26
}
27
28
uint8_t YM2413::Debuggable::read(unsigned address)
29
{
30
	const auto& ym2413 = OUTER(YM2413, debuggable);
31
	return ym2413.core->peekRegs()[address];
32
}
33
34
void YM2413::Debuggable::write(unsigned address, uint8_t value, EmuTime time)
35
{
36
	auto& ym2413 = OUTER(YM2413, debuggable);
37
	ym2413.pokeReg(narrow<uint8_t>(address), value, time);
38
}
39
40
41
// YM2413
42
43
static std::unique_ptr<YM2413Core> createCore(const DeviceConfig& config)
44
{
45
	auto core = config.getChildData("ym2413-core", "");
46
	if (core == "Okazaki") {
47
		return std::make_unique<YM2413Okazaki::YM2413>();
48
	} else if (core == "Burczynski") {
49
		return std::make_unique<YM2413Burczynski::YM2413>();
50
	} else if (core == "NukeYKT") {
51
		return std::make_unique<YM2413NukeYKT::YM2413>();
52
	} else if (core == "Original-NukeYKT") {
53
		return std::make_unique<YM2413OriginalNukeYKT::YM2413>(); // for debug
54
	} else if (core.empty()) {
55
		// The preferred way to select the core is via the <core> tag.
56
		// But for backwards compatibility, when that tag is missing,
57
		// fallback to using the <alternative> tag.
58
		if (config.getChildDataAsBool("alternative", false)) {
59
			return std::make_unique<YM2413Burczynski::YM2413>();
60
		} else {
61
			return std::make_unique<YM2413Okazaki::YM2413>();
62
		}
63
	}
64
	throw MSXException("Unknown YM2413 core '", core,
65
	                   "'. Must be one of 'Okazaki', 'Burczynski', 'NukeYKT', 'Original-NukeYKT'.");
66
}
67
68
static constexpr auto INPUT_RATE = unsigned(cstd::round(YM2413Core::CLOCK_FREQ / 72.0));
69
70
YM2413::YM2413(const std::string& name_, const DeviceConfig& config)
71
	: ResampledSoundDevice(config.getMotherBoard(), name_, "MSX-MUSIC", 9 + 5, INPUT_RATE, false)
72
	, core(createCore(config))
73
	, debuggable(config.getMotherBoard(), getName())
74
{
75
	registerSound(config);
76
}
77
78
YM2413::~YM2413()
79
{
80
	unregisterSound();
81
}
82
83
void YM2413::reset(EmuTime time)
84
{
85
	updateStream(time);
86
	core->reset();
87
}
88
89
void YM2413::writePort(bool port, uint8_t value, EmuTime time)
90
{
91
	updateStream(time);
92
93
	auto [integral, fractional] = getEmuClock().getTicksTillAsIntFloat(time);
94
	auto offset = narrow_cast<int>(18 * fractional);
95
	assert(integral == 0);
96
	assert(offset >= 0);
97
	assert(offset < 18);
98
99
	core->writePort(port, value, offset);
100
}
101
102
void YM2413::pokeReg(uint8_t reg, uint8_t value, EmuTime time)
103
{
104
	updateStream(time);
105
	core->pokeReg(reg, value);
106
}
107
108
std::span<const uint8_t, 64> YM2413::peekRegs() const
109
{
110
	return core->peekRegs();
111
}
112
113
void YM2413::setOutputRate(unsigned hostSampleRate, double speed)
114
{
115
	ResampledSoundDevice::setOutputRate(hostSampleRate, speed);
116
	core->setSpeed(speed);
117
}
118
119
void YM2413::generateChannels(std::span<float*> bufs, unsigned num)
120
{
121
	assert(bufs.size() == 9 + 5);
122
	core->generateChannels(bufs.first<9 + 5>(), num);
123
}
124
125
float YM2413::getAmplificationFactorImpl() const
126
{
127
	return core->getAmplificationFactor();
128
}
129
130
131
template<typename Archive>
132
void YM2413::serialize(Archive& ar, unsigned /*version*/)
133
{
134
	ar.serializePolymorphic("ym2413", *core);
135
}
136
INSTANTIATE_SERIALIZE_METHODS(YM2413);
137
138
} // namespace openmsx