OXYGENHUB
◆ main openmsx / src / sound / MSXTurboRPCM.cc
3.5 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#include "MSXTurboRPCM.hh"
2
3
#include "MSXMixer.hh"
4
#include "MSXMotherBoard.hh"
5
#include "serialize.hh"
6
7
#include "narrow.hh"
8
#include "unreachable.hh"
9
10
namespace openmsx {
11
12
MSXTurboRPCM::MSXTurboRPCM(const DeviceConfig& config)
13
	: MSXDevice(config)
14
	, mixer(getMotherBoard().getMSXMixer())
15
	, connector(getPluggingController(), "pcminput")
16
	, dac("PCM", "Turbo-R PCM", config)
17
	, reference(getCurrentTime())
18
{
19
	reset(getCurrentTime());
20
}
21
22
MSXTurboRPCM::~MSXTurboRPCM()
23
{
24
	hardwareMute(false);
25
}
26
27
void MSXTurboRPCM::reset(EmuTime time)
28
{
29
	reference.reset(time);
30
	status = 0;
31
	DValue = 0x80; // TODO correct initial value?
32
	hold = 0x80; // avoid UMR
33
	dac.reset(time);
34
	hardwareMute(false);
35
}
36
37
byte MSXTurboRPCM::readIO(uint16_t port, EmuTime time)
38
{
39
	return peekIO(port, time);
40
}
41
42
byte MSXTurboRPCM::peekIO(uint16_t port, EmuTime time) const
43
{
44
	switch (port & 0x01) {
45
	case 0:
46
		// bit 0-1  15.700kHz counter
47
		// bit 2-7  not used
48
		return reference.getTicksTill(time) & 0x03;
49
	case 1:
50
		// bit 0   BUFF  0->D/A    TODO check this bit
51
		//               1->A/D
52
		// bit 1   MUTE  mute ALL sound  0->muted
53
		// bit 2   FILT  filter  0->standard signal
54
		//                       1->filtered signal
55
		// bit 3   SEL   select 0->D/A
56
		//                      1->Mic/Jack
57
		// bit 4   SMPL  sample/hold  0->sample
58
		//                            1->hold
59
		// bit 5-6       not used
60
		// bit 7   COMP  comparator result 0->greater
61
		//                                 1->smaller
62
		return (getComp(time) ? 0x80 : 0x00) | (status & 0x1F);
63
	default:
64
		UNREACHABLE;
65
	}
66
}
67
68
void MSXTurboRPCM::writeIO(uint16_t port, byte value, EmuTime time)
69
{
70
	switch (port & 0x01) {
71
	case 0:
72
		// While playing: sample value
73
		//       recording: compare value
74
		// Resets counter
75
		reference.advance(time);
76
		DValue = value;
77
		if (status & 0x02) { // not muted
78
			assert(reference.getTime() <= time);
79
			auto time2 = (status & 0x01) // BUFF
80
			           ? reference.getFastAdd(1) // value only updates on the next clock
81
			           : time;
82
			assert(time <= time2);
83
			dac.writeDAC(DValue, time2);
84
		}
85
		break;
86
87
	case 1:
88
		// bit 0   BUFF
89
		// bit 1   MUTE  mute _all_ sound  0->no sound
90
		// bit 2   FILT  filter  1->filter on
91
		// bit 3   SEL   select  1->Mic/Jack  0->D/A
92
		// bit 4   SMPL  sample/hold  1->hold
93
		// bit 5-7  not used
94
		byte change = status ^ value;
95
		status = value;
96
97
		if ((change & 0x01) && ((status & 0x01) == 0)) {
98
			dac.writeDAC(DValue, time);
99
		}
100
		// TODO status & 0x08
101
		if ((change & 0x10) && (status & 0x10)) {
102
			hold = getSample(time);
103
		}
104
		hardwareMute(!(status & 0x02));
105
		break;
106
	}
107
}
108
109
byte MSXTurboRPCM::getSample(EmuTime time) const
110
{
111
	return (status & 0x04)
112
		? narrow<byte>((connector.readSample(time) / 256) + 0x80)
113
		: 0x80; // TODO check
114
}
115
116
bool MSXTurboRPCM::getComp(EmuTime time) const
117
{
118
	// TODO also when D/A ??
119
	byte sample = (status & 0x10) ? hold : getSample(time);
120
	return sample >= DValue;
121
}
122
123
void MSXTurboRPCM::hardwareMute(bool mute)
124
{
125
	if (mute == hwMute) return;
126
127
	hwMute = mute;
128
	if (hwMute) {
129
		mixer.mute();
130
	} else {
131
		mixer.unmute();
132
	}
133
}
134
135
136
template<typename Archive>
137
void MSXTurboRPCM::serialize(Archive& ar, unsigned /*version*/)
138
{
139
	ar.template serializeBase<MSXDevice>(*this);
140
	ar.serialize("audioConnector", connector,
141
	             "reference",      reference,
142
	             "status",         status,
143
	             "DValue",         DValue,
144
	             "hold",           hold,
145
	             "DAC",            dac);
146
147
	hardwareMute(!(status & 0x02));  // restore hwMute
148
}
149
INSTANTIATE_SERIALIZE_METHODS(MSXTurboRPCM);
150
REGISTER_MSXDEVICE(MSXTurboRPCM, "TurboR-PCM");
151
152
} // namespace openmsx