115 static constexpr
auto INPUT_RATE = unsigned(
cstd::round(3579545.0 / 32));
126 config.getMotherBoard(), name_, calcDescription(mode), 5, INPUT_RATE, false)
127 , debuggable(config.getMotherBoard(),
getName())
129 , currentChipMode(mode)
158 for (
auto& w1 : wave) {
162 for (
auto i :
xrange(5)) {
163 setFreqVol(i + 10, 15, time);
170 for (
auto i :
xrange(2 * 5)) {
171 setFreqVol(i, 0, time);
181 setDeformRegHelper(0);
192 currentChipMode = newMode;
201 if (((currentChipMode ==
SCC_Real) && (addr >= 0xE0)) ||
202 ((currentChipMode !=
SCC_Real) && (0xC0 <= addr) && (addr < 0xE0))) {
203 setDeformReg(0xFF, time);
210 switch (currentChipMode) {
212 if (address < 0x80) {
214 return readWave(address >> 5, address, time);
222 if (address < 0x80) {
224 return readWave(address >> 5, address, time);
225 }
else if (address < 0xA0) {
228 }
else if (address < 0xC0) {
230 return readWave(4, address, time);
237 if (address < 0xA0) {
239 return readWave(address >> 5, address, time);
251 byte SCC::readWave(
unsigned channel,
unsigned address, EmuTime::param time)
const
253 if (!rotate[channel]) {
254 return wave[channel][address & 0x1F];
257 unsigned periodCh = ((channel == 3) &&
259 ((deformValue & 0xC0) == 0x40))
261 unsigned shift = ticks / (period[periodCh] + 1);
262 return wave[channel][(address + shift) & 0x1F];
267 byte SCC::getFreqVol(
unsigned address)
const
270 if (address < 0x0A) {
272 unsigned channel = address / 2;
274 return orgPeriod[channel] >> 8;
276 return orgPeriod[channel] & 0xFF;
278 }
else if (address < 0x0F) {
280 return volume[address - 0xA];
291 switch (currentChipMode) {
293 if (address < 0x80) {
295 writeWave(address >> 5, address, value);
296 }
else if (address < 0xA0) {
298 setFreqVol(address, value, time);
299 }
else if (address < 0xE0) {
303 setDeformReg(value, time);
307 if (address < 0x80) {
309 writeWave(address >> 5, address, value);
310 }
else if (address < 0xA0) {
312 setFreqVol(address, value, time);
313 }
else if (address < 0xC0) {
315 }
else if (address < 0xE0) {
317 setDeformReg(value, time);
323 if (address < 0xA0) {
325 writeWave(address >> 5, address, value);
326 }
else if (address < 0xC0) {
328 setFreqVol(address, value, time);
329 }
else if (address < 0xE0) {
331 setDeformReg(value, time);
341 float SCC::getAmplificationFactorImpl()
const
343 return 1.0f / 128.0f;
346 static constexpr
float adjust(
signed char wav,
byte vol)
351 return float((
int(wav) * vol) >> 4);
354 void SCC::writeWave(
unsigned channel,
unsigned address,
byte value)
358 assert((channel != 4) || (currentChipMode ==
SCC_plusmode));
360 if (!readOnly[channel]) {
361 unsigned p = address & 0x1F;
362 wave[channel][p] = value;
363 volAdjustedWave[channel][p] = adjust(value, volume[channel]);
364 if ((currentChipMode !=
SCC_plusmode) && (channel == 3)) {
366 wave[4][p] = wave[3][p];
367 volAdjustedWave[4][p] = adjust(value, volume[4]);
372 void SCC::setFreqVol(
unsigned address,
byte value, EmuTime::param time)
375 if (address < 0x0A) {
377 unsigned channel = address / 2;
380 ? ((value & 0xF) << 8) | (orgPeriod[channel] & 0xFF)
381 : (orgPeriod[channel] & 0xF00) | (value & 0xFF);
382 orgPeriod[channel] = per;
383 if (deformValue & 2) {
386 }
else if (deformValue & 1) {
390 period[channel] = per;
391 incr[channel] = (per <= 8) ? 0 : 32;
393 if (deformValue & 0x20) {
400 out[channel] = volAdjustedWave[channel][pos[channel]];
401 }
else if (address < 0x0F) {
403 unsigned channel = address - 0x0A;
404 volume[channel] = value & 0xF;
405 for (
auto i :
xrange(32)) {
406 volAdjustedWave[channel][i] =
407 adjust(wave[channel][i], volume[channel]);
415 void SCC::setDeformReg(
byte value, EmuTime::param time)
417 if (value == deformValue) {
421 setDeformRegHelper(value);
424 void SCC::setDeformRegHelper(
byte value)
430 switch (value & 0xC0) {
440 for (
auto i :
xrange(3)) {
444 for (
auto i :
xrange(3, 5)) {
450 for (
auto i :
xrange(3)) {
454 for (
auto i :
xrange(3, 5)) {
464 void SCC::generateChannels(
float** bufs,
unsigned num)
466 unsigned enable = ch_enable;
467 for (
unsigned i = 0; i < 5; ++i, enable >>= 1) {
468 if ((enable & 1) && (volume[i] || out[i])) {
470 unsigned count2 = count[i];
471 unsigned pos2 = pos[i];
472 unsigned incr2 = incr[i];
473 unsigned period2 = period[i] + 1;
474 for (
auto j :
xrange(num)) {
479 while (
unlikely(count2 >= period2)) {
481 pos2 = (pos2 + 1) % 32;
482 out2 = volAdjustedWave[i][pos2];
491 unsigned newCount = count[i] + num * incr[i];
492 count[i] = newCount % (period[i] + 1);
493 pos[i] = (pos[i] + newCount / (period[i] + 1)) % 32;
503 SCC::Debuggable::Debuggable(MSXMotherBoard& motherBoard_,
const string& name_)
504 : SimpleDebuggable(motherBoard_, name_ +
" SCC",
505 "SCC registers in SCC+ format", 0x100)
509 byte SCC::Debuggable::read(
unsigned address, EmuTime::param time)
512 if (address < 0xA0) {
514 return scc.readWave(address >> 5, address, time);
515 }
else if (address < 0xC0) {
517 return scc.getFreqVol(address);
518 }
else if (address < 0xE0) {
520 return scc.deformValue;
526 void SCC::Debuggable::write(
unsigned address,
byte value, EmuTime::param time)
529 if (address < 0xA0) {
531 scc.writeWave(address >> 5, address, value);
532 }
else if (address < 0xC0) {
534 scc.setFreqVol(address, value, time);
535 }
else if (address < 0xE0) {
537 scc.setDeformReg(value, time);
544 static constexpr std::initializer_list<enum_string<SCC::ChipMode>> chipModeInfo = {
551 template<
typename Archive>
554 ar.serialize(
"mode", currentChipMode,
557 "ch_enable", ch_enable,
558 "deformTimer", deformTimer,
559 "deform", deformValue);
563 char tag[6] = {
'w',
'a',
'v',
'e',
'X', 0 };
564 for (
auto [channel, wv] :
enumerate(wave)) {
565 tag[4] = char(
'1' + channel);
566 ar.serialize(tag, wv);
571 for (
auto channel :
xrange(5)) {
572 for (
auto p :
xrange(32)) {
573 volAdjustedWave[channel][p] =
574 adjust(wave[channel][p], volume[channel]);
579 setDeformRegHelper(deformValue);
586 EmuTime::param time = deformTimer.
getTime();
587 for (
auto channel :
xrange(5)) {
588 unsigned per = orgPeriod[channel];
589 setFreqVol(2 * channel + 0, (per & 0x0FF) >> 0, time);
590 setFreqVol(2 * channel + 1, (per & 0xF00) >> 8, time);
595 ar.serialize(
"count", count,
constexpr EmuTime::param getTime() const
Gets the time at which the last clock tick occurred.
constexpr void advance(EmuTime::param e)
Advance this clock in time until the last tick which is not past the given time.
constexpr unsigned getTicksTill(EmuTime::param e) const
Calculate the number of ticks for this clock until the given time.
void writeMem(byte address, byte value, EmuTime::param time)
void setChipMode(ChipMode newMode)
void serialize(Archive &ar, unsigned version)
void powerUp(EmuTime::param time)
byte readMem(byte address, EmuTime::param time)
void reset(EmuTime::param time)
SCC(const std::string &name, const DeviceConfig &config, EmuTime::param time, ChipMode mode=SCC_Real)
byte peekMem(byte address, EmuTime::param time) const
void updateStream(EmuTime::param time)
void unregisterSound()
Unregisters this sound device with the Mixer.
void registerSound(const DeviceConfig &config)
Registers this sound device with the Mixer.
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
constexpr double round(double x)
string getName(KeyCode keyCode)
Translate key code to key name.
This file implemented 3 utility functions:
SERIALIZE_ENUM(CassettePlayer::State, stateInfo)
void fill(ForwardRange &&range, const T &value)
#define OUTER(type, member)
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
constexpr auto xrange(T e)