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