| ... | ... |
@@ -461,7 +461,7 @@ void Channel::Update() |
| 461 | 461 |
this->reg.totalLength = this->reg.loopStart + this->reg.length; |
| 462 | 462 |
this->ampl = AMPL_THRESHOLD; |
| 463 | 463 |
this->state = ChannelState::Attack; |
| 464 |
- // fallthrough |
|
| 464 |
+ [[fallthrough]]; |
|
| 465 | 465 |
case ChannelState::Attack: |
| 466 | 466 |
{
|
| 467 | 467 |
int newAmpl = this->ampl; |
* Use enum class instead of enum (except for the enums for the resource IDs, not really necessary there).
* For NCSF specifically, included a function to convert an enum class to its underlying integral type (as this is needed for use with the std::bitset class).
* Cleanup headers so all the ones needed in a file are explicitly included even if they may possibly be included in another header.
* Used forward declarations in a few spots.
* Explicitly namespaced all (u)int*_t uses (this might seem like overkill, but it helps me see when the standard types are being used with a simple search for std::).
* Made sure it all builds with MinGW-w64 as well (both gcc and clang).
* Removed some std::move from DialogBuilder.cpp based on clang's warnings for that.
* Replaced use of std::copy_n on strings in DialogBuilder.cpp with my CopyToString functions that use wcscpy.
* Replaced CHAR_MIN/CHAR_MAX in eqstr.h and ltstr.h with std::numeric_limits<char>::min/max().
| ... | ... |
@@ -10,10 +10,19 @@ |
| 10 | 10 |
* http://desmume.org/ |
| 11 | 11 |
*/ |
| 12 | 12 |
|
| 13 |
-#include "XSFCommon.h" |
|
| 13 |
+#include <algorithm> |
|
| 14 |
+#include <vector> |
|
| 15 |
+#define _USE_MATH_DEFINES |
|
| 16 |
+#include <cmath> |
|
| 17 |
+#include <cstddef> |
|
| 18 |
+#include <cstdint> |
|
| 14 | 19 |
#include "Channel.h" |
| 15 | 20 |
#include "Player.h" |
| 21 |
+#include "SWAV.h" |
|
| 22 |
+#include "Track.h" |
|
| 23 |
+#include "XSFCommon.h" |
|
| 16 | 24 |
#include "common.h" |
| 25 |
+#include "consts.h" |
|
| 17 | 26 |
|
| 18 | 27 |
NDSSoundRegister::NDSSoundRegister() : volumeMul(0), volumeDiv(0), panning(0), waveDuty(0), repeatMode(0), format(0), enable(false), |
| 19 | 28 |
source(nullptr), timer(0), psgX(0), psgLast(0), psgLastCount(0), samplePosition(0), sampleIncrease(0), loopStart(0), length(0), totalLength(0) |
| ... | ... |
@@ -26,7 +35,7 @@ void NDSSoundRegister::ClearControlRegister() |
| 26 | 35 |
this->enable = false; |
| 27 | 36 |
} |
| 28 | 37 |
|
| 29 |
-void NDSSoundRegister::SetControlRegister(uint32_t reg) |
|
| 38 |
+void NDSSoundRegister::SetControlRegister(std::uint32_t reg) |
|
| 30 | 39 |
{
|
| 31 | 40 |
this->volumeMul = reg & 0x7F; |
| 32 | 41 |
this->volumeDiv = (reg >> 8) & 0x03; |
| ... | ... |
@@ -54,7 +63,7 @@ static inline double sinc(double x) |
| 54 | 63 |
return fEqual(x, 0.0) ? 1.0 : std::sin(x * M_PI) / (x * M_PI); |
| 55 | 64 |
} |
| 56 | 65 |
|
| 57 |
-Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0), manualSweep(false), flags(), pan(0), extAmpl(0), velocity(0), extPan(0), |
|
| 66 |
+Channel::Channel() : chnId(-1), tempReg(), state(ChannelState::None), trackId(-1), prio(0), manualSweep(false), flags(), pan(0), extAmpl(0), velocity(0), extPan(0), |
|
| 58 | 67 |
key(0), ampl(0), extTune(0), orgKey(0), modType(0), modSpeed(0), modDepth(0), modRange(0), modDelay(0), modDelayCnt(0), modCounter(0), |
| 59 | 68 |
sweepLen(0), sweepCnt(0), sweepPitch(0), attackLvl(0), sustainLvl(0x7F), decayRate(0), releaseRate(0xFFFF), noteLength(-1), vol(0), ply(nullptr), reg(), |
| 60 | 69 |
ringBuffer() |
| ... | ... |
@@ -114,7 +123,7 @@ void Channel::UpdatePorta(const Track &trk) |
| 114 | 123 |
this->manualSweep = false; |
| 115 | 124 |
this->sweepPitch = trk.sweepPitch; |
| 116 | 125 |
this->sweepCnt = 0; |
| 117 |
- if (!trk.state[TS_PORTABIT]) |
|
| 126 |
+ if (!trk.state[ToIntegral(TrackState::PortamentoBit)]) |
|
| 118 | 127 |
{
|
| 119 | 128 |
this->sweepLen = 0; |
| 120 | 129 |
return; |
| ... | ... |
@@ -130,7 +139,7 @@ void Channel::UpdatePorta(const Track &trk) |
| 130 | 139 |
} |
| 131 | 140 |
else |
| 132 | 141 |
{
|
| 133 |
- int sq_time = static_cast<uint32_t>(trk.portaTime) * static_cast<uint32_t>(trk.portaTime); |
|
| 142 |
+ int sq_time = static_cast<std::uint32_t>(trk.portaTime) * static_cast<std::uint32_t>(trk.portaTime); |
|
| 134 | 143 |
int abs_sp = std::abs(this->sweepPitch); |
| 135 | 144 |
this->sweepLen = (abs_sp * sq_time) >> 11; |
| 136 | 145 |
} |
| ... | ... |
@@ -141,13 +150,13 @@ void Channel::Release() |
| 141 | 150 |
{
|
| 142 | 151 |
this->noteLength = -1; |
| 143 | 152 |
this->prio = 1; |
| 144 |
- this->state = CS_RELEASE; |
|
| 153 |
+ this->state = ChannelState::Release; |
|
| 145 | 154 |
} |
| 146 | 155 |
|
| 147 | 156 |
// Original FSS Function: Chn_Kill |
| 148 | 157 |
void Channel::Kill() |
| 149 | 158 |
{
|
| 150 |
- this->state = CS_NONE; |
|
| 159 |
+ this->state = ChannelState::None; |
|
| 151 | 160 |
this->trackId = -1; |
| 152 | 161 |
this->prio = 0; |
| 153 | 162 |
this->reg.ClearControlRegister(); |
| ... | ... |
@@ -155,18 +164,16 @@ void Channel::Kill() |
| 155 | 164 |
this->noteLength = -1; |
| 156 | 165 |
} |
| 157 | 166 |
|
| 158 |
-static inline int getModFlag(int type) |
|
| 167 |
+static inline ChannelFlag getModFlag(int type) |
|
| 159 | 168 |
{
|
| 160 | 169 |
switch (type) |
| 161 | 170 |
{
|
| 162 | 171 |
case 0: |
| 163 |
- return CF_UPDTMR; |
|
| 164 |
- case 1: |
|
| 165 |
- return CF_UPDVOL; |
|
| 172 |
+ return ChannelFlag::UpdateTimer; |
|
| 166 | 173 |
case 2: |
| 167 |
- return CF_UPDPAN; |
|
| 168 |
- default: |
|
| 169 |
- return 0; |
|
| 174 |
+ return ChannelFlag::UpdatePan; |
|
| 175 |
+ default: // basically 1 |
|
| 176 |
+ return ChannelFlag::UpdateVolume; |
|
| 170 | 177 |
} |
| 171 | 178 |
} |
| 172 | 179 |
|
| ... | ... |
@@ -185,46 +192,46 @@ void Channel::UpdateTrack() |
| 185 | 192 |
if (trackFlags.none()) |
| 186 | 193 |
return; |
| 187 | 194 |
|
| 188 |
- if (trackFlags[TUF_LEN]) |
|
| 195 |
+ if (trackFlags[ToIntegral(TrackUpdateFlag::Length)]) |
|
| 189 | 196 |
{
|
| 190 |
- int st = this->state; |
|
| 191 |
- if (st > CS_START) |
|
| 197 |
+ ChannelState st = this->state; |
|
| 198 |
+ if (st > ChannelState::Start) |
|
| 192 | 199 |
{
|
| 193 |
- if (st < CS_RELEASE && !--this->noteLength) |
|
| 200 |
+ if (st < ChannelState::Release && !--this->noteLength) |
|
| 194 | 201 |
this->Release(); |
| 195 | 202 |
if (this->manualSweep && this->sweepCnt < this->sweepLen) |
| 196 | 203 |
++this->sweepCnt; |
| 197 | 204 |
} |
| 198 | 205 |
} |
| 199 |
- if (trackFlags[TUF_VOL]) |
|
| 206 |
+ if (trackFlags[ToIntegral(TrackUpdateFlag::Volume)]) |
|
| 200 | 207 |
{
|
| 201 | 208 |
this->UpdateVol(trk); |
| 202 |
- this->flags.set(CF_UPDVOL); |
|
| 209 |
+ this->flags.set(ToIntegral(ChannelFlag::UpdateVolume)); |
|
| 203 | 210 |
} |
| 204 |
- if (trackFlags[TUF_PAN]) |
|
| 211 |
+ if (trackFlags[ToIntegral(TrackUpdateFlag::Pan)]) |
|
| 205 | 212 |
{
|
| 206 | 213 |
this->UpdatePan(trk); |
| 207 |
- this->flags.set(CF_UPDPAN); |
|
| 214 |
+ this->flags.set(ToIntegral(ChannelFlag::UpdatePan)); |
|
| 208 | 215 |
} |
| 209 |
- if (trackFlags[TUF_TIMER]) |
|
| 216 |
+ if (trackFlags[ToIntegral(TrackUpdateFlag::Timer)]) |
|
| 210 | 217 |
{
|
| 211 | 218 |
this->UpdateTune(trk); |
| 212 |
- this->flags.set(CF_UPDTMR); |
|
| 219 |
+ this->flags.set(ToIntegral(ChannelFlag::UpdateTimer)); |
|
| 213 | 220 |
} |
| 214 |
- if (trackFlags[TUF_MOD]) |
|
| 221 |
+ if (trackFlags[ToIntegral(TrackUpdateFlag::Modulation)]) |
|
| 215 | 222 |
{
|
| 216 | 223 |
int oldType = this->modType; |
| 217 | 224 |
int newType = trk.modType; |
| 218 | 225 |
this->UpdateMod(trk); |
| 219 | 226 |
if (oldType != newType) |
| 220 | 227 |
{
|
| 221 |
- this->flags.set(getModFlag(oldType)); |
|
| 222 |
- this->flags.set(getModFlag(newType)); |
|
| 228 |
+ this->flags.set(ToIntegral(getModFlag(oldType))); |
|
| 229 |
+ this->flags.set(ToIntegral(getModFlag(newType))); |
|
| 223 | 230 |
} |
| 224 | 231 |
} |
| 225 | 232 |
} |
| 226 | 233 |
|
| 227 |
-static const uint16_t getpitchtbl[] = |
|
| 234 |
+static const std::uint16_t getpitchtbl[] = |
|
| 228 | 235 |
{
|
| 229 | 236 |
0x0000, 0x003B, 0x0076, 0x00B2, 0x00ED, 0x0128, 0x0164, 0x019F, |
| 230 | 237 |
0x01DB, 0x0217, 0x0252, 0x028E, 0x02CA, 0x0305, 0x0341, 0x037D, |
| ... | ... |
@@ -324,7 +331,7 @@ static const uint16_t getpitchtbl[] = |
| 324 | 331 |
0xFC51, 0xFCC7, 0xFD3C, 0xFDB2, 0xFE28, 0xFE9E, 0xFF14, 0xFF8A |
| 325 | 332 |
}; |
| 326 | 333 |
|
| 327 |
-static const uint8_t getvoltbl[] = |
|
| 334 |
+static const std::uint8_t getvoltbl[] = |
|
| 328 | 335 |
{
|
| 329 | 336 |
0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
| 330 | 337 |
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
| ... | ... |
@@ -375,7 +382,7 @@ static const uint8_t getvoltbl[] = |
| 375 | 382 |
}; |
| 376 | 383 |
|
| 377 | 384 |
// This function was obtained through disassembly of Ninty's sound driver |
| 378 |
-static inline uint16_t Timer_Adjust(uint16_t basetmr, int pitch) |
|
| 385 |
+static inline std::uint16_t Timer_Adjust(std::uint16_t basetmr, int pitch) |
|
| 379 | 386 |
{
|
| 380 | 387 |
int shift = 0; |
| 381 | 388 |
pitch = -pitch; |
| ... | ... |
@@ -392,7 +399,7 @@ static inline uint16_t Timer_Adjust(uint16_t basetmr, int pitch) |
| 392 | 399 |
pitch -= 0x300; |
| 393 | 400 |
} |
| 394 | 401 |
|
| 395 |
- uint64_t tmr = static_cast<uint64_t>(basetmr) * (static_cast<uint32_t>(getpitchtbl[pitch]) + 0x10000); |
|
| 402 |
+ std::uint64_t tmr = static_cast<std::uint64_t>(basetmr) * (static_cast<std::uint32_t>(getpitchtbl[pitch]) + 0x10000); |
|
| 396 | 403 |
shift -= 16; |
| 397 | 404 |
if (shift <= 0) |
| 398 | 405 |
tmr >>= -shift; |
| ... | ... |
@@ -409,7 +416,7 @@ static inline uint16_t Timer_Adjust(uint16_t basetmr, int pitch) |
| 409 | 416 |
return 0x10; |
| 410 | 417 |
if (tmr > 0xFFFF) |
| 411 | 418 |
return 0xFFFF; |
| 412 |
- return static_cast<uint16_t>(tmr); |
|
| 419 |
+ return static_cast<std::uint16_t>(tmr); |
|
| 413 | 420 |
} |
| 414 | 421 |
|
| 415 | 422 |
static inline int calcVolDivShift(int x) |
| ... | ... |
@@ -427,35 +434,35 @@ static inline int calcVolDivShift(int x) |
| 427 | 434 |
void Channel::Update() |
| 428 | 435 |
{
|
| 429 | 436 |
// Kill active channels that aren't physically active |
| 430 |
- if (this->state > CS_START && !this->reg.enable) |
|
| 437 |
+ if (this->state > ChannelState::Start && !this->reg.enable) |
|
| 431 | 438 |
{
|
| 432 | 439 |
this->Kill(); |
| 433 | 440 |
return; |
| 434 | 441 |
} |
| 435 | 442 |
|
| 436 |
- bool bNotInSustain = this->state != CS_SUSTAIN; |
|
| 437 |
- bool bInStart = this->state == CS_START; |
|
| 443 |
+ bool bNotInSustain = this->state != ChannelState::Sustain; |
|
| 444 |
+ bool bInStart = this->state == ChannelState::Start; |
|
| 438 | 445 |
bool bPitchSweep = this->sweepPitch && this->sweepLen && this->sweepCnt <= this->sweepLen; |
| 439 | 446 |
bool bModulation = !!this->modDepth; |
| 440 |
- bool bVolNeedUpdate = this->flags[CF_UPDVOL] || bNotInSustain; |
|
| 441 |
- bool bPanNeedUpdate = this->flags[CF_UPDPAN] || bInStart; |
|
| 442 |
- bool bTmrNeedUpdate = this->flags[CF_UPDTMR] || bInStart || bPitchSweep; |
|
| 447 |
+ bool bVolNeedUpdate = this->flags[ToIntegral(ChannelFlag::UpdateVolume)] || bNotInSustain; |
|
| 448 |
+ bool bPanNeedUpdate = this->flags[ToIntegral(ChannelFlag::UpdatePan)] || bInStart; |
|
| 449 |
+ bool bTmrNeedUpdate = this->flags[ToIntegral(ChannelFlag::UpdateTimer)] || bInStart || bPitchSweep; |
|
| 443 | 450 |
int modParam = 0; |
| 444 | 451 |
|
| 445 | 452 |
switch (this->state) |
| 446 | 453 |
{
|
| 447 |
- case CS_NONE: |
|
| 454 |
+ case ChannelState::None: |
|
| 448 | 455 |
return; |
| 449 |
- case CS_START: |
|
| 456 |
+ case ChannelState::Start: |
|
| 450 | 457 |
this->reg.ClearControlRegister(); |
| 451 | 458 |
this->reg.source = this->tempReg.SOURCE; |
| 452 | 459 |
this->reg.loopStart = this->tempReg.REPEAT_POINT; |
| 453 | 460 |
this->reg.length = this->tempReg.LENGTH; |
| 454 | 461 |
this->reg.totalLength = this->reg.loopStart + this->reg.length; |
| 455 | 462 |
this->ampl = AMPL_THRESHOLD; |
| 456 |
- this->state = CS_ATTACK; |
|
| 463 |
+ this->state = ChannelState::Attack; |
|
| 457 | 464 |
// fallthrough |
| 458 |
- case CS_ATTACK: |
|
| 465 |
+ case ChannelState::Attack: |
|
| 459 | 466 |
{
|
| 460 | 467 |
int newAmpl = this->ampl; |
| 461 | 468 |
int oldAmpl = this->ampl >> 7; |
| ... | ... |
@@ -464,21 +471,21 @@ void Channel::Update() |
| 464 | 471 |
while ((newAmpl >> 7) == oldAmpl); |
| 465 | 472 |
this->ampl = newAmpl; |
| 466 | 473 |
if (!this->ampl) |
| 467 |
- this->state = CS_DECAY; |
|
| 474 |
+ this->state = ChannelState::Decay; |
|
| 468 | 475 |
break; |
| 469 | 476 |
} |
| 470 |
- case CS_DECAY: |
|
| 477 |
+ case ChannelState::Decay: |
|
| 471 | 478 |
{
|
| 472 | 479 |
this->ampl -= static_cast<int>(this->decayRate); |
| 473 | 480 |
int sustLvl = Cnv_Sust(this->sustainLvl) << 7; |
| 474 | 481 |
if (this->ampl <= sustLvl) |
| 475 | 482 |
{
|
| 476 | 483 |
this->ampl = sustLvl; |
| 477 |
- this->state = CS_SUSTAIN; |
|
| 484 |
+ this->state = ChannelState::Sustain; |
|
| 478 | 485 |
} |
| 479 | 486 |
break; |
| 480 | 487 |
} |
| 481 |
- case CS_RELEASE: |
|
| 488 |
+ case ChannelState::Release: |
|
| 482 | 489 |
this->ampl -= static_cast<int>(this->releaseRate); |
| 483 | 490 |
if (this->ampl <= AMPL_THRESHOLD) |
| 484 | 491 |
{
|
| ... | ... |
@@ -511,12 +518,12 @@ void Channel::Update() |
| 511 | 518 |
modParam = Cnv_Sine(this->modCounter >> 8) * this->modRange * this->modDepth; // 7.14 |
| 512 | 519 |
|
| 513 | 520 |
if (this->modType == 1) |
| 514 |
- modParam = static_cast<int64_t>(modParam * 60) >> 14; // vol: adjust range to 6dB = 60cB (no fractional bits) |
|
| 521 |
+ modParam = static_cast<std::int64_t>(modParam * 60) >> 14; // vol: adjust range to 6dB = 60cB (no fractional bits) |
|
| 515 | 522 |
else |
| 516 | 523 |
modParam >>= 8; // tmr/pan: adjust to 7.6 |
| 517 | 524 |
|
| 518 | 525 |
// Update the modulation variables |
| 519 |
- uint32_t counter = this->modCounter + (this->modSpeed << 6); |
|
| 526 |
+ std::uint32_t counter = this->modCounter + (this->modSpeed << 6); |
|
| 520 | 527 |
while (counter >= 0x8000) |
| 521 | 528 |
counter -= 0x8000; |
| 522 | 529 |
this->modCounter = counter; |
| ... | ... |
@@ -531,22 +538,22 @@ void Channel::Update() |
| 531 | 538 |
{
|
| 532 | 539 |
int len = this->sweepLen; |
| 533 | 540 |
int cnt = this->sweepCnt; |
| 534 |
- totalAdj += (static_cast<int64_t>(this->sweepPitch) * (len - cnt)) / len; |
|
| 541 |
+ totalAdj += (static_cast<std::int64_t>(this->sweepPitch) * (len - cnt)) / len; |
|
| 535 | 542 |
if (!this->manualSweep) |
| 536 | 543 |
++this->sweepCnt; |
| 537 | 544 |
} |
| 538 |
- uint16_t tmr = this->tempReg.TIMER; |
|
| 545 |
+ std::uint16_t tmr = this->tempReg.TIMER; |
|
| 539 | 546 |
|
| 540 | 547 |
if (totalAdj) |
| 541 | 548 |
tmr = Timer_Adjust(tmr, totalAdj); |
| 542 | 549 |
this->reg.timer = -tmr; |
| 543 | 550 |
this->reg.sampleIncrease = (ARM7_CLOCK / static_cast<double>(this->ply->sampleRate * 2)) / (0x10000 - this->reg.timer); |
| 544 |
- this->flags.reset(CF_UPDTMR); |
|
| 551 |
+ this->flags.reset(ToIntegral(ChannelFlag::UpdateTimer)); |
|
| 545 | 552 |
} |
| 546 | 553 |
|
| 547 | 554 |
if (bVolNeedUpdate || bPanNeedUpdate) |
| 548 | 555 |
{
|
| 549 |
- uint32_t cr = this->tempReg.CR; |
|
| 556 |
+ std::uint32_t cr = this->tempReg.CR; |
|
| 550 | 557 |
if (bVolNeedUpdate) |
| 551 | 558 |
{
|
| 552 | 559 |
int totalVol = this->ampl >> 7; |
| ... | ... |
@@ -569,7 +576,7 @@ void Channel::Update() |
| 569 | 576 |
|
| 570 | 577 |
this->vol = ((cr & SOUND_VOL(0x7F)) << 4) >> calcVolDivShift((cr & SOUND_VOLDIV(3)) >> 8); |
| 571 | 578 |
|
| 572 |
- this->flags.reset(CF_UPDVOL); |
|
| 579 |
+ this->flags.reset(ToIntegral(ChannelFlag::UpdateVolume)); |
|
| 573 | 580 |
} |
| 574 | 581 |
|
| 575 | 582 |
if (bPanNeedUpdate) |
| ... | ... |
@@ -583,7 +590,7 @@ void Channel::Update() |
| 583 | 590 |
|
| 584 | 591 |
cr &= ~SOUND_PAN(0x7F); |
| 585 | 592 |
cr |= SOUND_PAN(realPan); |
| 586 |
- this->flags.reset(CF_UPDPAN); |
|
| 593 |
+ this->flags.reset(ToIntegral(ChannelFlag::UpdatePan)); |
|
| 587 | 594 |
} |
| 588 | 595 |
|
| 589 | 596 |
this->tempReg.CR = cr; |
| ... | ... |
@@ -591,7 +598,7 @@ void Channel::Update() |
| 591 | 598 |
} |
| 592 | 599 |
} |
| 593 | 600 |
|
| 594 |
-static const int16_t wavedutytbl[8][8] = |
|
| 601 |
+static const std::int16_t wavedutytbl[8][8] = |
|
| 595 | 602 |
{
|
| 596 | 603 |
{ -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF },
|
| 597 | 604 |
{ -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF },
|
| ... | ... |
@@ -606,14 +613,14 @@ static const int16_t wavedutytbl[8][8] = |
| 606 | 613 |
// Linear interpolation code originally from DeSmuME |
| 607 | 614 |
// Legrange comes from Olli Niemitalo: |
| 608 | 615 |
// http://www.student.oulu.fi/~oniemita/dsp/deip.pdf |
| 609 |
-int32_t Channel::Interpolate() |
|
| 616 |
+std::int32_t Channel::Interpolate() |
|
| 610 | 617 |
{
|
| 611 | 618 |
double ratio = this->reg.samplePosition; |
| 612 |
- ratio -= static_cast<int32_t>(ratio); |
|
| 619 |
+ ratio -= static_cast<std::int32_t>(ratio); |
|
| 613 | 620 |
|
| 614 | 621 |
const auto &data = this->ringBuffer.GetBuffer(); |
| 615 | 622 |
|
| 616 |
- if (this->ply->interpolation == INTERPOLATION_SINC) |
|
| 623 |
+ if (this->ply->interpolation == Interpolation::Sinc) |
|
| 617 | 624 |
{
|
| 618 | 625 |
double kernel[SINC_WIDTH * 2], kernel_sum = 0.0; |
| 619 | 626 |
int i = SINC_WIDTH, shift = static_cast<int>(std::floor(ratio * SINC_RESOLUTION)); |
| ... | ... |
@@ -629,13 +636,13 @@ int32_t Channel::Interpolate() |
| 629 | 636 |
double sum = 0.0; |
| 630 | 637 |
for (i = 0; i < static_cast<int>(SINC_WIDTH * 2); ++i) |
| 631 | 638 |
sum += data[i - static_cast<int>(SINC_WIDTH) + 1] * kernel[i]; |
| 632 |
- return static_cast<int32_t>(sum / kernel_sum); |
|
| 639 |
+ return static_cast<std::int32_t>(sum / kernel_sum); |
|
| 633 | 640 |
} |
| 634 |
- else if (this->ply->interpolation > INTERPOLATION_LINEAR) |
|
| 641 |
+ else if (this->ply->interpolation > Interpolation::Linear) |
|
| 635 | 642 |
{
|
| 636 | 643 |
double c0, c1, c2, c3, c4, c5; |
| 637 | 644 |
|
| 638 |
- if (this->ply->interpolation == INTERPOLATION_6POINTLEGRANGE) |
|
| 645 |
+ if (this->ply->interpolation == Interpolation::SixPointLegrange) |
|
| 639 | 646 |
{
|
| 640 | 647 |
ratio -= 0.5; |
| 641 | 648 |
double even1 = data[-2] + data[3], odd1 = data[-2] - data[3]; |
| ... | ... |
@@ -647,30 +654,30 @@ int32_t Channel::Interpolate() |
| 647 | 654 |
c3 = 1 / 48.0 * odd1 - 13 / 48.0 * odd2 + 17 / 24.0 * odd3; |
| 648 | 655 |
c4 = 1 / 48.0 * even1 - 0.0625 * even2 + 1 / 24.0 * even3; |
| 649 | 656 |
c5 = 1 / 24.0 * odd2 - 1 / 12.0 * odd3 - 1 / 120.0 * odd1; |
| 650 |
- return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 657 |
+ return static_cast<std::int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 651 | 658 |
} |
| 652 |
- else // INTERPOLATION_4POINTLEAGRANGE |
|
| 659 |
+ else // 4-Point Legrange |
|
| 653 | 660 |
{
|
| 654 | 661 |
c0 = data[0]; |
| 655 | 662 |
c1 = data[1] - 1 / 3.0 * data[-1] - 0.5 * data[0] - 1 / 6.0 * data[2]; |
| 656 | 663 |
c2 = 0.5 * (data[-1] + data[1]) - data[0]; |
| 657 | 664 |
c3 = 1 / 6.0 * (data[2] - data[-1]) + 0.5 * (data[0] - data[1]); |
| 658 |
- return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 665 |
+ return static_cast<std::int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 659 | 666 |
} |
| 660 | 667 |
} |
| 661 |
- else // INTERPOLATION_LINEAR |
|
| 662 |
- return static_cast<int32_t>(data[0] + ratio * (data[1] - data[0])); |
|
| 668 |
+ else // Linear |
|
| 669 |
+ return static_cast<std::int32_t>(data[0] + ratio * (data[1] - data[0])); |
|
| 663 | 670 |
} |
| 664 | 671 |
|
| 665 |
-int32_t Channel::GenerateSample() |
|
| 672 |
+std::int32_t Channel::GenerateSample() |
|
| 666 | 673 |
{
|
| 667 | 674 |
if (this->reg.samplePosition < 0) |
| 668 | 675 |
return 0; |
| 669 | 676 |
|
| 670 | 677 |
if (this->reg.format != 3) |
| 671 | 678 |
{
|
| 672 |
- if (this->ply->interpolation == INTERPOLATION_NONE) |
|
| 673 |
- return this->reg.source->dataptr[static_cast<uint32_t>(this->reg.samplePosition)]; |
|
| 679 |
+ if (this->ply->interpolation == Interpolation::None) |
|
| 680 |
+ return this->reg.source->dataptr[static_cast<std::uint32_t>(this->reg.samplePosition)]; |
|
| 674 | 681 |
else |
| 675 | 682 |
return this->Interpolate(); |
| 676 | 683 |
} |
| ... | ... |
@@ -679,13 +686,13 @@ int32_t Channel::GenerateSample() |
| 679 | 686 |
if (this->chnId < 8) |
| 680 | 687 |
return 0; |
| 681 | 688 |
else if (this->chnId < 14) |
| 682 |
- return wavedutytbl[this->reg.waveDuty][static_cast<uint32_t>(this->reg.samplePosition) & 0x7]; |
|
| 689 |
+ return wavedutytbl[this->reg.waveDuty][static_cast<std::uint32_t>(this->reg.samplePosition) & 0x7]; |
|
| 683 | 690 |
else |
| 684 | 691 |
{
|
| 685 |
- if (this->reg.psgLastCount != static_cast<uint32_t>(this->reg.samplePosition)) |
|
| 692 |
+ if (this->reg.psgLastCount != static_cast<std::uint32_t>(this->reg.samplePosition)) |
|
| 686 | 693 |
{
|
| 687 |
- uint32_t max = static_cast<uint32_t>(this->reg.samplePosition); |
|
| 688 |
- for (uint32_t i = this->reg.psgLastCount; i < max; ++i) |
|
| 694 |
+ std::uint32_t max = static_cast<std::uint32_t>(this->reg.samplePosition); |
|
| 695 |
+ for (std::uint32_t i = this->reg.psgLastCount; i < max; ++i) |
|
| 689 | 696 |
{
|
| 690 | 697 |
if (this->reg.psgX & 0x1) |
| 691 | 698 |
{
|
| ... | ... |
@@ -699,7 +706,7 @@ int32_t Channel::GenerateSample() |
| 699 | 706 |
} |
| 700 | 707 |
} |
| 701 | 708 |
|
| 702 |
- this->reg.psgLastCount = static_cast<uint32_t>(this->reg.samplePosition); |
|
| 709 |
+ this->reg.psgLastCount = static_cast<std::uint32_t>(this->reg.samplePosition); |
|
| 703 | 710 |
} |
| 704 | 711 |
|
| 705 | 712 |
return this->reg.psgLast; |
| ... | ... |
@@ -717,17 +724,17 @@ void Channel::IncrementSample() |
| 717 | 724 |
{
|
| 718 | 725 |
this->ringBuffer.Clear(); |
| 719 | 726 |
this->ringBuffer.bufferPos += SINC_WIDTH + 1; |
| 720 |
- auto preData = std::vector<int16_t>(SINC_WIDTH + 1, this->reg.source->dataptr[0]); |
|
| 727 |
+ auto preData = std::vector<std::int16_t>(SINC_WIDTH + 1, this->reg.source->dataptr[0]); |
|
| 721 | 728 |
this->ringBuffer.PushSamples(&preData[0], SINC_WIDTH + 1); |
| 722 | 729 |
if (this->reg.totalLength < SINC_WIDTH + 1) |
| 723 | 730 |
{
|
| 724 | 731 |
this->ringBuffer.PushSamples(&this->reg.source->dataptr[0], this->reg.totalLength); |
| 725 | 732 |
if (this->reg.repeatMode == 1) |
| 726 | 733 |
{
|
| 727 |
- size_t samplesLeft = SINC_WIDTH + 1 - this->reg.totalLength; |
|
| 734 |
+ std::size_t samplesLeft = SINC_WIDTH + 1 - this->reg.totalLength; |
|
| 728 | 735 |
while (samplesLeft) |
| 729 | 736 |
{
|
| 730 |
- size_t samplesToPush = std::min(samplesLeft, this->reg.length); |
|
| 737 |
+ std::size_t samplesToPush = std::min(samplesLeft, this->reg.length); |
|
| 731 | 738 |
this->ringBuffer.PushSamples(&this->reg.source->dataptr[this->reg.loopStart], samplesToPush); |
| 732 | 739 |
samplesLeft -= samplesToPush; |
| 733 | 740 |
} |
| ... | ... |
@@ -738,8 +745,8 @@ void Channel::IncrementSample() |
| 738 | 745 |
} |
| 739 | 746 |
if (this->reg.samplePosition >= 0) |
| 740 | 747 |
{
|
| 741 |
- uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition) + SINC_WIDTH + 1; |
|
| 742 |
- uint32_t newloc = static_cast<uint32_t>(samplePosition) + SINC_WIDTH + 1; |
|
| 748 |
+ std::uint32_t loc = static_cast<std::uint32_t>(this->reg.samplePosition) + SINC_WIDTH + 1; |
|
| 749 |
+ std::uint32_t newloc = static_cast<std::uint32_t>(samplePosition) + SINC_WIDTH + 1; |
|
| 743 | 750 |
|
| 744 | 751 |
if (this->reg.repeatMode == 1) |
| 745 | 752 |
{
|
(I never remember to update these and besides, GitHub history can show when they were last modified.)
| ... | ... |
@@ -455,7 +455,7 @@ void Channel::Update() |
| 455 | 455 |
this->reg.totalLength = this->reg.loopStart + this->reg.length; |
| 456 | 456 |
this->ampl = AMPL_THRESHOLD; |
| 457 | 457 |
this->state = CS_ATTACK; |
| 458 |
- // Fall down |
|
| 458 |
+ // fallthrough |
|
| 459 | 459 |
case CS_ATTACK: |
| 460 | 460 |
{
|
| 461 | 461 |
int newAmpl = this->ampl; |
* While I am unsure if this would've ever happened, this will prevent the locations from being out-of-bounds.
| ... | ... |
@@ -744,9 +744,9 @@ void Channel::IncrementSample() |
| 744 | 744 |
|
| 745 | 745 |
if (this->reg.repeatMode == 1) |
| 746 | 746 |
{
|
| 747 |
- if (loc >= this->reg.totalLength) |
|
| 747 |
+ while (loc >= this->reg.totalLength) |
|
| 748 | 748 |
loc -= this->reg.length; |
| 749 |
- if (newloc >= this->reg.totalLength) |
|
| 749 |
+ while (newloc >= this->reg.totalLength) |
|
| 750 | 750 |
newloc -= this->reg.length; |
| 751 | 751 |
} |
| 752 | 752 |
|
| ... | ... |
@@ -509,25 +509,18 @@ void Channel::Update() |
| 509 | 509 |
} |
| 510 | 510 |
|
| 511 | 511 |
// Get the current modulation parameter |
| 512 |
- modParam = Cnv_Sine(this->modCounter >> 8) * this->modRange * this->modDepth; |
|
| 512 |
+ modParam = Cnv_Sine(this->modCounter >> 8) * this->modRange * this->modDepth; // 7.14 |
|
| 513 | 513 |
|
| 514 |
- if (!this->modType) |
|
| 515 |
- modParam = static_cast<int64_t>(modParam * 60) >> 14; |
|
| 514 |
+ if (this->modType == 1) |
|
| 515 |
+ modParam = static_cast<int64_t>(modParam * 60) >> 14; // vol: adjust range to 6dB = 60cB (no fractional bits) |
|
| 516 | 516 |
else |
| 517 |
- // This ugly formula whose exact meaning and workings I cannot figure out is used for volume/pan modulation. |
|
| 518 |
- modParam = ((modParam & ~0xFC000000) >> 8) | ((((modParam < 0 ? -1 : 0) << 6) | (static_cast<uint32_t>(modParam) >> 26)) << 18); |
|
| 517 |
+ modParam >>= 8; // tmr/pan: adjust to 7.6 |
|
| 519 | 518 |
|
| 520 | 519 |
// Update the modulation variables |
| 521 |
- |
|
| 522 |
- uint16_t speed = static_cast<uint16_t>(this->modSpeed) << 6; |
|
| 523 |
- uint16_t counter = (this->modCounter + speed) >> 8; |
|
| 524 |
- |
|
| 525 |
- while (counter >= 0x80) |
|
| 526 |
- counter -= 0x80; |
|
| 527 |
- |
|
| 528 |
- this->modCounter += speed; |
|
| 529 |
- this->modCounter &= 0xFF; |
|
| 530 |
- this->modCounter |= counter << 8; |
|
| 520 |
+ uint32_t counter = this->modCounter + (this->modSpeed << 6); |
|
| 521 |
+ while (counter >= 0x8000) |
|
| 522 |
+ counter -= 0x8000; |
|
| 523 |
+ this->modCounter += counter; |
|
| 531 | 524 |
} |
| 532 | 525 |
|
| 533 | 526 |
if (bTmrNeedUpdate) |
Sinc mode should not scale the window, just the sinc pulse.
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2014-10-23 |
|
| 4 |
+ * Last modification on 2014-10-27 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -44,6 +44,7 @@ TempSndReg::TempSndReg() : CR(0), SOURCE(nullptr), TIMER(0), REPEAT_POINT(0), LE |
| 44 | 44 |
|
| 45 | 45 |
bool Channel::initializedLUTs = false; |
| 46 | 46 |
double Channel::sinc_lut[Channel::SINC_SAMPLES + 1]; |
| 47 |
+double Channel::window_lut[Channel::SINC_SAMPLES + 1]; |
|
| 47 | 48 |
|
| 48 | 49 |
#ifndef M_PI |
| 49 | 50 |
static const double M_PI = 3.14159265358979323846; |
| ... | ... |
@@ -65,7 +66,8 @@ Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0), |
| 65 | 66 |
for (unsigned i = 0; i <= SINC_SAMPLES; ++i, x += dx) |
| 66 | 67 |
{
|
| 67 | 68 |
double y = x / SINC_WIDTH; |
| 68 |
- this->sinc_lut[i] = std::abs(x) < SINC_WIDTH ? sinc(x) * (0.40897 + 0.5 * std::cos(M_PI * y) + 0.09103 * std::cos(2 * M_PI * y)) : 0.0; |
|
| 69 |
+ this->sinc_lut[i] = std::abs(x) < SINC_WIDTH ? sinc(x) : 0.0; |
|
| 70 |
+ this->window_lut[i] = 0.40897 + 0.5 * std::cos(M_PI * y) + 0.09103 * std::cos(2 * M_PI * y); |
|
| 69 | 71 |
} |
| 70 | 72 |
this->initializedLUTs = true; |
| 71 | 73 |
} |
| ... | ... |
@@ -625,10 +627,12 @@ int32_t Channel::Interpolate() |
| 625 | 627 |
int i = SINC_WIDTH, shift = static_cast<int>(std::floor(ratio * SINC_RESOLUTION)); |
| 626 | 628 |
int step = this->reg.sampleIncrease > 1.0 ? static_cast<int>(SINC_RESOLUTION / this->reg.sampleIncrease) : SINC_RESOLUTION; |
| 627 | 629 |
int shift_adj = shift * step / SINC_RESOLUTION; |
| 630 |
+ int window_step = SINC_RESOLUTION; |
|
| 628 | 631 |
for (; i >= -static_cast<int>(SINC_WIDTH - 1); --i) |
| 629 | 632 |
{
|
| 630 | 633 |
int pos = i * step; |
| 631 |
- kernel_sum += kernel[i + SINC_WIDTH - 1] = this->sinc_lut[std::abs(shift_adj - pos)]; |
|
| 634 |
+ int window_pos = i * window_step; |
|
| 635 |
+ kernel_sum += kernel[i + SINC_WIDTH - 1] = this->sinc_lut[std::abs(shift_adj - pos)] * this->window_lut[std::abs(shift - window_pos)]; |
|
| 632 | 636 |
} |
| 633 | 637 |
double sum = 0.0; |
| 634 | 638 |
for (i = 0; i < static_cast<int>(SINC_WIDTH * 2); ++i) |
| ... | ... |
@@ -64,7 +64,7 @@ Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0), |
| 64 | 64 |
double dx = static_cast<double>(SINC_WIDTH) / SINC_SAMPLES, x = 0.0; |
| 65 | 65 |
for (unsigned i = 0; i <= SINC_SAMPLES; ++i, x += dx) |
| 66 | 66 |
{
|
| 67 |
- float y = x / SINC_WIDTH; |
|
| 67 |
+ double y = x / SINC_WIDTH; |
|
| 68 | 68 |
this->sinc_lut[i] = std::abs(x) < SINC_WIDTH ? sinc(x) * (0.40897 + 0.5 * std::cos(M_PI * y) + 0.09103 * std::cos(2 * M_PI * y)) : 0.0; |
| 69 | 69 |
} |
| 70 | 70 |
this->initializedLUTs = true; |
* Changed default of modDelay to 0.
* Also minor cleanup.
| ... | ... |
@@ -71,6 +71,7 @@ Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0), |
| 71 | 71 |
} |
| 72 | 72 |
} |
| 73 | 73 |
|
| 74 |
+// Original FSS Function: Chn_UpdateVol |
|
| 74 | 75 |
void Channel::UpdateVol(const Track &trk) |
| 75 | 76 |
{
|
| 76 | 77 |
int finalVol = trk.ply->masterVol; |
| ... | ... |
@@ -82,11 +83,13 @@ void Channel::UpdateVol(const Track &trk) |
| 82 | 83 |
this->extAmpl = finalVol; |
| 83 | 84 |
} |
| 84 | 85 |
|
| 86 |
+// Original FSS Function: Chn_UpdatePan |
|
| 85 | 87 |
void Channel::UpdatePan(const Track &trk) |
| 86 | 88 |
{
|
| 87 | 89 |
this->extPan = trk.pan; |
| 88 | 90 |
} |
| 89 | 91 |
|
| 92 |
+// Original FSS Function: Chn_UpdateTune |
|
| 90 | 93 |
void Channel::UpdateTune(const Track &trk) |
| 91 | 94 |
{
|
| 92 | 95 |
int tune = (static_cast<int>(this->key) - static_cast<int>(this->orgKey)) * 64; |
| ... | ... |
@@ -94,6 +97,7 @@ void Channel::UpdateTune(const Track &trk) |
| 94 | 97 |
this->extTune = tune; |
| 95 | 98 |
} |
| 96 | 99 |
|
| 100 |
+// Original FSS Function: Chn_UpdateMod |
|
| 97 | 101 |
void Channel::UpdateMod(const Track &trk) |
| 98 | 102 |
{
|
| 99 | 103 |
this->modType = trk.modType; |
| ... | ... |
@@ -103,6 +107,7 @@ void Channel::UpdateMod(const Track &trk) |
| 103 | 107 |
this->modDelay = trk.modDelay; |
| 104 | 108 |
} |
| 105 | 109 |
|
| 110 |
+// Original FSS Function: Chn_UpdatePorta |
|
| 106 | 111 |
void Channel::UpdatePorta(const Track &trk) |
| 107 | 112 |
{
|
| 108 | 113 |
this->manualSweep = false; |
| ... | ... |
@@ -130,6 +135,7 @@ void Channel::UpdatePorta(const Track &trk) |
| 130 | 135 |
} |
| 131 | 136 |
} |
| 132 | 137 |
|
| 138 |
+// Original FSS Function: Chn_Release |
|
| 133 | 139 |
void Channel::Release() |
| 134 | 140 |
{
|
| 135 | 141 |
this->noteLength = -1; |
| ... | ... |
@@ -137,6 +143,7 @@ void Channel::Release() |
| 137 | 143 |
this->state = CS_RELEASE; |
| 138 | 144 |
} |
| 139 | 145 |
|
| 146 |
+// Original FSS Function: Chn_Kill |
|
| 140 | 147 |
void Channel::Kill() |
| 141 | 148 |
{
|
| 142 | 149 |
this->state = CS_NONE; |
| ... | ... |
@@ -162,6 +169,7 @@ static inline int getModFlag(int type) |
| 162 | 169 |
} |
| 163 | 170 |
} |
| 164 | 171 |
|
| 172 |
+// Original FSS Function: Chn_UpdateTracks |
|
| 165 | 173 |
void Channel::UpdateTrack() |
| 166 | 174 |
{
|
| 167 | 175 |
if (!this->ply) |
| ... | ... |
@@ -171,11 +179,11 @@ void Channel::UpdateTrack() |
| 171 | 179 |
if (trkn == -1) |
| 172 | 180 |
return; |
| 173 | 181 |
|
| 174 |
- auto &trackFlags = this->ply->tracks[trkn].updateFlags; |
|
| 182 |
+ auto &trk = this->ply->tracks[trkn]; |
|
| 183 |
+ auto &trackFlags = trk.updateFlags; |
|
| 175 | 184 |
if (trackFlags.none()) |
| 176 | 185 |
return; |
| 177 | 186 |
|
| 178 |
- auto &trk = this->ply->tracks[trkn]; |
|
| 179 | 187 |
if (trackFlags[TUF_LEN]) |
| 180 | 188 |
{
|
| 181 | 189 |
int st = this->state; |
| ... | ... |
@@ -414,6 +422,7 @@ static inline int calcVolDivShift(int x) |
| 414 | 422 |
return 4; |
| 415 | 423 |
} |
| 416 | 424 |
|
| 425 |
+// Original FSS Function: Snd_UpdChannel |
|
| 417 | 426 |
void Channel::Update() |
| 418 | 427 |
{
|
| 419 | 428 |
// Kill active channels that aren't physically active |
| ... | ... |
@@ -470,10 +479,11 @@ void Channel::Update() |
| 470 | 479 |
} |
| 471 | 480 |
case CS_RELEASE: |
| 472 | 481 |
this->ampl -= static_cast<int>(this->releaseRate); |
| 473 |
- if (this->ampl > AMPL_THRESHOLD) |
|
| 474 |
- break; |
|
| 475 |
- this->Kill(); |
|
| 476 |
- return; |
|
| 482 |
+ if (this->ampl <= AMPL_THRESHOLD) |
|
| 483 |
+ {
|
|
| 484 |
+ this->Kill(); |
|
| 485 |
+ return; |
|
| 486 |
+ } |
|
| 477 | 487 |
} |
| 478 | 488 |
|
| 479 | 489 |
if (bModulation && this->modDelayCnt < this->modDelay) |
| ... | ... |
@@ -575,10 +585,7 @@ void Channel::Update() |
| 575 | 585 |
if (bModulation && this->modType == 2) |
| 576 | 586 |
realPan += modParam; |
| 577 | 587 |
realPan += 64; |
| 578 |
- if (realPan < 0) |
|
| 579 |
- realPan = 0; |
|
| 580 |
- else if (realPan > 127) |
|
| 581 |
- realPan = 127; |
|
| 588 |
+ clamp(realPan, 0, 127); |
|
| 582 | 589 |
|
| 583 | 590 |
cr &= ~SOUND_PAN(0x7F); |
| 584 | 591 |
cr |= SOUND_PAN(realPan); |
| ... | ... |
@@ -63,7 +63,10 @@ Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0), |
| 63 | 63 |
{
|
| 64 | 64 |
double dx = static_cast<double>(SINC_WIDTH) / SINC_SAMPLES, x = 0.0; |
| 65 | 65 |
for (unsigned i = 0; i <= SINC_SAMPLES; ++i, x += dx) |
| 66 |
- this->sinc_lut[i] = std::abs(x) < SINC_WIDTH ? sinc(x) * sinc(x / SINC_WIDTH) : 0.0; |
|
| 66 |
+ {
|
|
| 67 |
+ float y = x / SINC_WIDTH; |
|
| 68 |
+ this->sinc_lut[i] = std::abs(x) < SINC_WIDTH ? sinc(x) * (0.40897 + 0.5 * std::cos(M_PI * y) + 0.09103 * std::cos(2 * M_PI * y)) : 0.0; |
|
| 69 |
+ } |
|
| 67 | 70 |
this->initializedLUTs = true; |
| 68 | 71 |
} |
| 69 | 72 |
} |
(Basically, it should never allow the same volume level as the previous
calculation.)
| ... | ... |
@@ -445,9 +445,10 @@ void Channel::Update() |
| 445 | 445 |
case CS_ATTACK: |
| 446 | 446 |
{
|
| 447 | 447 |
int newAmpl = this->ampl; |
| 448 |
+ int oldAmpl = this->ampl >> 7; |
|
| 448 | 449 |
do |
| 449 | 450 |
newAmpl = (newAmpl * static_cast<int>(this->attackLvl)) / 256; |
| 450 |
- while (newAmpl == this->ampl); |
|
| 451 |
+ while ((newAmpl >> 7) == oldAmpl); |
|
| 451 | 452 |
this->ampl = newAmpl; |
| 452 | 453 |
if (!this->ampl) |
| 453 | 454 |
this->state = CS_DECAY; |
| ... | ... |
@@ -443,10 +443,16 @@ void Channel::Update() |
| 443 | 443 |
this->state = CS_ATTACK; |
| 444 | 444 |
// Fall down |
| 445 | 445 |
case CS_ATTACK: |
| 446 |
- this->ampl = (this->ampl * static_cast<int>(this->attackLvl)) / 255; |
|
| 446 |
+ {
|
|
| 447 |
+ int newAmpl = this->ampl; |
|
| 448 |
+ do |
|
| 449 |
+ newAmpl = (newAmpl * static_cast<int>(this->attackLvl)) / 256; |
|
| 450 |
+ while (newAmpl == this->ampl); |
|
| 451 |
+ this->ampl = newAmpl; |
|
| 447 | 452 |
if (!this->ampl) |
| 448 | 453 |
this->state = CS_DECAY; |
| 449 | 454 |
break; |
| 455 |
+ } |
|
| 450 | 456 |
case CS_DECAY: |
| 451 | 457 |
{
|
| 452 | 458 |
this->ampl -= static_cast<int>(this->decayRate); |
| ... | ... |
@@ -536,6 +542,8 @@ void Channel::Update() |
| 536 | 542 |
if (bVolNeedUpdate) |
| 537 | 543 |
{
|
| 538 | 544 |
int totalVol = this->ampl >> 7; |
| 545 |
+ if (totalVol == -1) |
|
| 546 |
+ this->ampl = 0; |
|
| 539 | 547 |
totalVol += this->extAmpl; |
| 540 | 548 |
totalVol += this->velocity; |
| 541 | 549 |
if (bModulation && this->modType == 1) |
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2014-10-05 |
|
| 4 |
+ * Last modification on 2014-10-18 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -71,6 +71,7 @@ Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0), |
| 71 | 71 |
void Channel::UpdateVol(const Track &trk) |
| 72 | 72 |
{
|
| 73 | 73 |
int finalVol = trk.ply->masterVol; |
| 74 |
+ finalVol += trk.ply->sseqVol; |
|
| 74 | 75 |
finalVol += Cnv_Sust(trk.vol); |
| 75 | 76 |
finalVol += Cnv_Sust(trk.expr); |
| 76 | 77 |
if (finalVol < -AMPL_K) |
Also commented out the code that uses the SSEQ's volume, it seems as if
the DS doesn't use it so I probably shouldn't be using it either.
| ... | ... |
@@ -73,6 +73,8 @@ void Channel::UpdateVol(const Track &trk) |
| 73 | 73 |
int finalVol = trk.ply->masterVol; |
| 74 | 74 |
finalVol += Cnv_Sust(trk.vol); |
| 75 | 75 |
finalVol += Cnv_Sust(trk.expr); |
| 76 |
+ if (finalVol < -AMPL_K) |
|
| 77 |
+ finalVol = -AMPL_K; |
|
| 76 | 78 |
this->extAmpl = finalVol; |
| 77 | 79 |
} |
| 78 | 80 |
|
| ... | ... |
@@ -440,7 +442,7 @@ void Channel::Update() |
| 440 | 442 |
this->state = CS_ATTACK; |
| 441 | 443 |
// Fall down |
| 442 | 444 |
case CS_ATTACK: |
| 443 |
- this->ampl = (static_cast<int>(this->ampl) * static_cast<int>(this->attackLvl)) / 255; |
|
| 445 |
+ this->ampl = (this->ampl * static_cast<int>(this->attackLvl)) / 255; |
|
| 444 | 446 |
if (!this->ampl) |
| 445 | 447 |
this->state = CS_DECAY; |
| 446 | 448 |
break; |
| ... | ... |
@@ -537,19 +539,17 @@ void Channel::Update() |
| 537 | 539 |
totalVol += this->velocity; |
| 538 | 540 |
if (bModulation && this->modType == 1) |
| 539 | 541 |
totalVol += modParam; |
| 540 |
- if (totalVol < -AMPL_K) |
|
| 541 |
- totalVol = -AMPL_K; |
|
| 542 |
- else if (totalVol > 0) |
|
| 543 |
- totalVol = 0; |
|
| 542 |
+ totalVol += AMPL_K; |
|
| 543 |
+ clamp(totalVol, 0, AMPL_K); |
|
| 544 | 544 |
|
| 545 | 545 |
cr &= ~(SOUND_VOL(0x7F) | SOUND_VOLDIV(3)); |
| 546 |
- cr |= SOUND_VOL(static_cast<int>(getvoltbl[totalVol + AMPL_K])); |
|
| 546 |
+ cr |= SOUND_VOL(static_cast<int>(getvoltbl[totalVol])); |
|
| 547 | 547 |
|
| 548 |
- if (totalVol < -240) |
|
| 548 |
+ if (totalVol < AMPL_K - 240) |
|
| 549 | 549 |
cr |= SOUND_VOLDIV(3); |
| 550 |
- else if (totalVol < -120) |
|
| 550 |
+ else if (totalVol < AMPL_K - 120) |
|
| 551 | 551 |
cr |= SOUND_VOLDIV(2); |
| 552 |
- else if (totalVol < -60) |
|
| 552 |
+ else if (totalVol < AMPL_K - 60) |
|
| 553 | 553 |
cr |= SOUND_VOLDIV(1); |
| 554 | 554 |
|
| 555 | 555 |
this->vol = ((cr & SOUND_VOL(0x7F)) << 4) >> calcVolDivShift((cr & SOUND_VOLDIV(3)) >> 8); |
| ... | ... |
@@ -71,8 +71,8 @@ Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0), |
| 71 | 71 |
void Channel::UpdateVol(const Track &trk) |
| 72 | 72 |
{
|
| 73 | 73 |
int finalVol = trk.ply->masterVol; |
| 74 |
- finalVol += Cnv_Scale(trk.vol); |
|
| 75 |
- finalVol += Cnv_Scale(trk.expr); |
|
| 74 |
+ finalVol += Cnv_Sust(trk.vol); |
|
| 75 |
+ finalVol += Cnv_Sust(trk.expr); |
|
| 76 | 76 |
this->extAmpl = finalVol; |
| 77 | 77 |
} |
| 78 | 78 |
|
Also added a clone of DeSmuME's Sound View that is only build during a
debug build, which helped to identify the above issues.
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2014-06-17 |
|
| 4 |
+ * Last modification on 2014-10-05 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -71,10 +71,8 @@ Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0), |
| 71 | 71 |
void Channel::UpdateVol(const Track &trk) |
| 72 | 72 |
{
|
| 73 | 73 |
int finalVol = trk.ply->masterVol; |
| 74 |
- finalVol += Cnv_Sust(trk.vol); |
|
| 75 |
- finalVol += Cnv_Sust(trk.expr); |
|
| 76 |
- if (finalVol < -AMPL_K) |
|
| 77 |
- finalVol = -AMPL_K; |
|
| 74 |
+ finalVol += Cnv_Scale(trk.vol); |
|
| 75 |
+ finalVol += Cnv_Scale(trk.expr); |
|
| 78 | 76 |
this->extAmpl = finalVol; |
| 79 | 77 |
} |
| 80 | 78 |
|
| ... | ... |
@@ -390,7 +388,7 @@ static inline uint16_t Timer_Adjust(uint16_t basetmr, int pitch) |
| 390 | 388 |
tmr <<= shift; |
| 391 | 389 |
} |
| 392 | 390 |
else |
| 393 |
- return 0x10; |
|
| 391 |
+ return 0xFFFF; |
|
| 394 | 392 |
|
| 395 | 393 |
if (tmr < 0x10) |
| 396 | 394 |
return 0x10; |
| ... | ... |
@@ -539,18 +537,19 @@ void Channel::Update() |
| 539 | 537 |
totalVol += this->velocity; |
| 540 | 538 |
if (bModulation && this->modType == 1) |
| 541 | 539 |
totalVol += modParam; |
| 542 |
- totalVol += AMPL_K; |
|
| 543 |
- if (totalVol < 0) |
|
| 540 |
+ if (totalVol < -AMPL_K) |
|
| 541 |
+ totalVol = -AMPL_K; |
|
| 542 |
+ else if (totalVol > 0) |
|
| 544 | 543 |
totalVol = 0; |
| 545 | 544 |
|
| 546 | 545 |
cr &= ~(SOUND_VOL(0x7F) | SOUND_VOLDIV(3)); |
| 547 |
- cr |= SOUND_VOL(static_cast<int>(getvoltbl[totalVol])); |
|
| 546 |
+ cr |= SOUND_VOL(static_cast<int>(getvoltbl[totalVol + AMPL_K])); |
|
| 548 | 547 |
|
| 549 |
- if (totalVol < AMPL_K - 240) |
|
| 548 |
+ if (totalVol < -240) |
|
| 550 | 549 |
cr |= SOUND_VOLDIV(3); |
| 551 |
- else if (totalVol < AMPL_K - 120) |
|
| 550 |
+ else if (totalVol < -120) |
|
| 552 | 551 |
cr |= SOUND_VOLDIV(2); |
| 553 |
- else if (totalVol < AMPL_K - 60) |
|
| 552 |
+ else if (totalVol < -60) |
|
| 554 | 553 |
cr |= SOUND_VOLDIV(1); |
| 555 | 554 |
|
| 556 | 555 |
this->vol = ((cr & SOUND_VOL(0x7F)) << 4) >> calcVolDivShift((cr & SOUND_VOLDIV(3)) >> 8); |
| ... | ... |
@@ -592,8 +592,8 @@ static const int16_t wavedutytbl[8][8] = |
| 592 | 592 |
{ -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF }
|
| 593 | 593 |
}; |
| 594 | 594 |
|
| 595 |
-// Linear and Cosine interpolation code originally from DeSmuME |
|
| 596 |
-// B-spline and Osculating come from Olli Niemitalo: |
|
| 595 |
+// Linear interpolation code originally from DeSmuME |
|
| 596 |
+// Legrange comes from Olli Niemitalo: |
|
| 597 | 597 |
// http://www.student.oulu.fi/~oniemita/dsp/deip.pdf |
| 598 | 598 |
int32_t Channel::Interpolate() |
| 599 | 599 |
{
|
* Removed Cosine, 4-Point B-Spline, 6-Point B-Spline, and 6-point
Osculating.
* Added 4-Point Legrange and 6-Point Legrange.
* Changed wording of the Sinc interpolation to mention that it is
16-point.
| ... | ... |
@@ -43,7 +43,6 @@ TempSndReg::TempSndReg() : CR(0), SOURCE(nullptr), TIMER(0), REPEAT_POINT(0), LE |
| 43 | 43 |
} |
| 44 | 44 |
|
| 45 | 45 |
bool Channel::initializedLUTs = false; |
| 46 |
-double Channel::cosine_lut[Channel::COSINE_RESOLUTION]; |
|
| 47 | 46 |
double Channel::sinc_lut[Channel::SINC_SAMPLES + 1]; |
| 48 | 47 |
|
| 49 | 48 |
#ifndef M_PI |
| ... | ... |
@@ -62,8 +61,6 @@ Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0), |
| 62 | 61 |
{
|
| 63 | 62 |
if (!this->initializedLUTs) |
| 64 | 63 |
{
|
| 65 |
- for (unsigned i = 0; i < COSINE_RESOLUTION; ++i) |
|
| 66 |
- this->cosine_lut[i] = (1.0 - std::cos((static_cast<double>(i) / COSINE_RESOLUTION) * M_PI)) * 0.5; |
|
| 67 | 64 |
double dx = static_cast<double>(SINC_WIDTH) / SINC_SAMPLES, x = 0.0; |
| 68 | 65 |
for (unsigned i = 0; i <= SINC_SAMPLES; ++i, x += dx) |
| 69 | 66 |
this->sinc_lut[i] = std::abs(x) < SINC_WIDTH ? sinc(x) * sinc(x / SINC_WIDTH) : 0.0; |
| ... | ... |
@@ -621,52 +618,33 @@ int32_t Channel::Interpolate() |
| 621 | 618 |
sum += data[i - static_cast<int>(SINC_WIDTH) + 1] * kernel[i]; |
| 622 | 619 |
return static_cast<int32_t>(sum / kernel_sum); |
| 623 | 620 |
} |
| 624 |
- else if (this->ply->interpolation > INTERPOLATION_COSINE) |
|
| 621 |
+ else if (this->ply->interpolation > INTERPOLATION_LINEAR) |
|
| 625 | 622 |
{
|
| 626 | 623 |
double c0, c1, c2, c3, c4, c5; |
| 627 | 624 |
|
| 628 |
- if (this->ply->interpolation > INTERPOLATION_4POINTBSPLINE) |
|
| 625 |
+ if (this->ply->interpolation == INTERPOLATION_6POINTLEGRANGE) |
|
| 629 | 626 |
{
|
| 630 |
- if (this->ply->interpolation == INTERPOLATION_6POINTBSPLINE) |
|
| 631 |
- {
|
|
| 632 |
- double ym2py2 = data[-2] + data[2], ym1py1 = data[-1] + data[1]; |
|
| 633 |
- double y2mym2 = data[2] - data[-2], y1mym1 = data[1] - data[-1]; |
|
| 634 |
- double sixthym1py1 = 1 / 6.0 * ym1py1; |
|
| 635 |
- c0 = 1 / 120.0 * ym2py2 + 13 / 60.0 * ym1py1 + 0.55 * data[0]; |
|
| 636 |
- c1 = 1 / 24.0 * y2mym2 + 5 / 12.0 * y1mym1; |
|
| 637 |
- c2 = 1 / 12.0 * ym2py2 + sixthym1py1 - 0.5 * data[0]; |
|
| 638 |
- c3 = 1 / 12.0 * y2mym2 - 1 / 6.0 * y1mym1; |
|
| 639 |
- c4 = 1 / 24.0 * ym2py2 - sixthym1py1 + 0.25 * data[0]; |
|
| 640 |
- c5 = 1 / 120.0 * (data[3] - data[-2]) + 1 / 24.0 * (data[-1] - data[2]) + 1 / 12.0 * (data[1] - data[0]); |
|
| 641 |
- return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 642 |
- } |
|
| 643 |
- else // INTERPOLATION_6POINTOSCULATING |
|
| 644 |
- {
|
|
| 645 |
- ratio -= 0.5; |
|
| 646 |
- double even1 = data[-2] + data[3], odd1 = data[-2] - data[3]; |
|
| 647 |
- double even2 = data[-1] + data[2], odd2 = data[-1] - data[2]; |
|
| 648 |
- double even3 = data[0] + data[1], odd3 = data[0] - data[1]; |
|
| 649 |
- c0 = 0.01171875 * even1 - 0.09765625 * even2 + 0.5859375 * even3; |
|
| 650 |
- c1 = 0.2109375 * odd2 - 281 / 192.0 * odd3 - 13 / 384.0 * odd1; |
|
| 651 |
- c2 = 0.40625 * even2 - 17 / 48.0 * even3 - 5 / 96.0 * even1; |
|
| 652 |
- c3 = 0.1875 * odd1 - 53 / 48.0 * odd2 + 2.375 * odd3; |
|
| 653 |
- c4 = 1 / 48.0 * even1 - 0.0625 * even2 + 1 / 24.0 * even3; |
|
| 654 |
- c5 = 25 / 24.0 * odd2 - 25 / 12.0 * odd3 - 5 / 24.0 * odd1; |
|
| 655 |
- return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 656 |
- } |
|
| 627 |
+ ratio -= 0.5; |
|
| 628 |
+ double even1 = data[-2] + data[3], odd1 = data[-2] - data[3]; |
|
| 629 |
+ double even2 = data[-1] + data[2], odd2 = data[-1] - data[2]; |
|
| 630 |
+ double even3 = data[0] + data[1], odd3 = data[0] - data[1]; |
|
| 631 |
+ c0 = 0.01171875 * even1 - 0.09765625 * even2 + 0.5859375 * even3; |
|
| 632 |
+ c1 = 25 / 384.0 * odd2 - 1.171875 * odd3 - 0.0046875 * odd1; |
|
| 633 |
+ c2 = 0.40625 * even2 - 17 / 48.0 * even3 - 5 / 96.0 * even1; |
|
| 634 |
+ c3 = 1 / 48.0 * odd1 - 13 / 48.0 * odd2 + 17 / 24.0 * odd3; |
|
| 635 |
+ c4 = 1 / 48.0 * even1 - 0.0625 * even2 + 1 / 24.0 * even3; |
|
| 636 |
+ c5 = 1 / 24.0 * odd2 - 1 / 12.0 * odd3 - 1 / 120.0 * odd1; |
|
| 637 |
+ return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 657 | 638 |
} |
| 658 |
- else // INTERPOLATION_4POINTBSPLINE |
|
| 639 |
+ else // INTERPOLATION_4POINTLEAGRANGE |
|
| 659 | 640 |
{
|
| 660 |
- double ym1py1 = data[-1] + data[1]; |
|
| 661 |
- c0 = 1 / 6.0 * ym1py1 + 2 / 3.0 * data[0]; |
|
| 662 |
- c1 = 0.5 * (data[1] - data[-1]); |
|
| 663 |
- c2 = 0.5 * ym1py1 - data[0]; |
|
| 664 |
- c3 = 0.5 * (data[0] - data[1]) + 1 / 6.0 * (data[2] - data[-1]); |
|
| 641 |
+ c0 = data[0]; |
|
| 642 |
+ c1 = data[1] - 1 / 3.0 * data[-1] - 0.5 * data[0] - 1 / 6.0 * data[2]; |
|
| 643 |
+ c2 = 0.5 * (data[-1] + data[1]) - data[0]; |
|
| 644 |
+ c3 = 1 / 6.0 * (data[2] - data[-1]) + 0.5 * (data[0] - data[1]); |
|
| 665 | 645 |
return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0); |
| 666 | 646 |
} |
| 667 | 647 |
} |
| 668 |
- else if (this->ply->interpolation == INTERPOLATION_COSINE) |
|
| 669 |
- return static_cast<int32_t>(data[0] + this->cosine_lut[static_cast<unsigned>(ratio * COSINE_RESOLUTION)] * (data[1] - data[0])); |
|
| 670 | 648 |
else // INTERPOLATION_LINEAR |
| 671 | 649 |
return static_cast<int32_t>(data[0] + ratio * (data[1] - data[0])); |
| 672 | 650 |
} |
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2013-05-07 |
|
| 4 |
+ * Last modification on 2014-06-17 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -66,7 +66,7 @@ Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0), |
| 66 | 66 |
this->cosine_lut[i] = (1.0 - std::cos((static_cast<double>(i) / COSINE_RESOLUTION) * M_PI)) * 0.5; |
| 67 | 67 |
double dx = static_cast<double>(SINC_WIDTH) / SINC_SAMPLES, x = 0.0; |
| 68 | 68 |
for (unsigned i = 0; i <= SINC_SAMPLES; ++i, x += dx) |
| 69 |
- this->sinc_lut[i] = std::abs(x) < SINC_WIDTH ? sinc(x) * (0.5 * (1.0 + std::cos((M_PI * x) / SINC_WIDTH))) : 0.0; |
|
| 69 |
+ this->sinc_lut[i] = std::abs(x) < SINC_WIDTH ? sinc(x) * sinc(x / SINC_WIDTH) : 0.0; |
|
| 70 | 70 |
this->initializedLUTs = true; |
| 71 | 71 |
} |
| 72 | 72 |
} |
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2013-04-26 |
|
| 4 |
+ * Last modification on 2013-05-07 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -44,7 +44,7 @@ TempSndReg::TempSndReg() : CR(0), SOURCE(nullptr), TIMER(0), REPEAT_POINT(0), LE |
| 44 | 44 |
|
| 45 | 45 |
bool Channel::initializedLUTs = false; |
| 46 | 46 |
double Channel::cosine_lut[Channel::COSINE_RESOLUTION]; |
| 47 |
-double Channel::lanczos_lut[Channel::LANCZOS_SAMPLES + 1]; |
|
| 47 |
+double Channel::sinc_lut[Channel::SINC_SAMPLES + 1]; |
|
| 48 | 48 |
|
| 49 | 49 |
#ifndef M_PI |
| 50 | 50 |
static const double M_PI = 3.14159265358979323846; |
| ... | ... |
@@ -57,16 +57,16 @@ static inline double sinc(double x) |
| 57 | 57 |
|
| 58 | 58 |
Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0), manualSweep(false), flags(), pan(0), extAmpl(0), velocity(0), extPan(0), |
| 59 | 59 |
key(0), ampl(0), extTune(0), orgKey(0), modType(0), modSpeed(0), modDepth(0), modRange(0), modDelay(0), modDelayCnt(0), modCounter(0), |
| 60 |
- sweepLen(0), sweepCnt(0), sweepPitch(0), attackLvl(0), sustainLvl(0x7F), decayRate(0), releaseRate(0xFFFF), noteLength(-1), vol(0), ply(nullptr), reg() |
|
| 60 |
+ sweepLen(0), sweepCnt(0), sweepPitch(0), attackLvl(0), sustainLvl(0x7F), decayRate(0), releaseRate(0xFFFF), noteLength(-1), vol(0), ply(nullptr), reg(), |
|
| 61 |
+ ringBuffer() |
|
| 61 | 62 |
{
|
| 62 |
- this->clearHistory(); |
|
| 63 | 63 |
if (!this->initializedLUTs) |
| 64 | 64 |
{
|
| 65 | 65 |
for (unsigned i = 0; i < COSINE_RESOLUTION; ++i) |
| 66 | 66 |
this->cosine_lut[i] = (1.0 - std::cos((static_cast<double>(i) / COSINE_RESOLUTION) * M_PI)) * 0.5; |
| 67 |
- double dx = static_cast<double>(LANCZOS_WIDTH) / LANCZOS_SAMPLES, x = 0.0; |
|
| 68 |
- for (unsigned i = 0; i <= LANCZOS_SAMPLES; ++i, x += dx) |
|
| 69 |
- this->lanczos_lut[i] = std::abs(x) < LANCZOS_WIDTH ? sinc(x) * sinc(x / LANCZOS_WIDTH) : 0.0; |
|
| 67 |
+ double dx = static_cast<double>(SINC_WIDTH) / SINC_SAMPLES, x = 0.0; |
|
| 68 |
+ for (unsigned i = 0; i <= SINC_SAMPLES; ++i, x += dx) |
|
| 69 |
+ this->sinc_lut[i] = std::abs(x) < SINC_WIDTH ? sinc(x) * (0.5 * (1.0 + std::cos((M_PI * x) / SINC_WIDTH))) : 0.0; |
|
| 70 | 70 |
this->initializedLUTs = true; |
| 71 | 71 |
} |
| 72 | 72 |
} |
| ... | ... |
@@ -144,7 +144,6 @@ void Channel::Kill() |
| 144 | 144 |
this->reg.ClearControlRegister(); |
| 145 | 145 |
this->vol = 0; |
| 146 | 146 |
this->noteLength = -1; |
| 147 |
- this->clearHistory(); |
|
| 148 | 147 |
} |
| 149 | 148 |
|
| 150 | 149 |
static inline int getModFlag(int type) |
| ... | ... |
@@ -604,22 +603,22 @@ int32_t Channel::Interpolate() |
| 604 | 603 |
double ratio = this->reg.samplePosition; |
| 605 | 604 |
ratio -= static_cast<int32_t>(ratio); |
| 606 | 605 |
|
| 607 |
- const auto &data = &this->sampleHistory[this->sampleHistoryPtr + 16]; |
|
| 606 |
+ const auto &data = this->ringBuffer.GetBuffer(); |
|
| 608 | 607 |
|
| 609 |
- if (this->ply->interpolation == INTERPOLATION_LANCZOS) |
|
| 608 |
+ if (this->ply->interpolation == INTERPOLATION_SINC) |
|
| 610 | 609 |
{
|
| 611 |
- double kernel[LANCZOS_WIDTH * 2], kernel_sum = 0.0; |
|
| 612 |
- int i = LANCZOS_WIDTH, shift = static_cast<int>(std::floor(ratio * LANCZOS_RESOLUTION)); |
|
| 613 |
- int step = this->reg.sampleIncrease > 1.0 ? static_cast<int>(LANCZOS_RESOLUTION / this->reg.sampleIncrease) : LANCZOS_RESOLUTION; |
|
| 614 |
- int shift_adj = shift * step / LANCZOS_RESOLUTION; |
|
| 615 |
- for (; i >= -static_cast<int>(LANCZOS_WIDTH - 1); --i) |
|
| 610 |
+ double kernel[SINC_WIDTH * 2], kernel_sum = 0.0; |
|
| 611 |
+ int i = SINC_WIDTH, shift = static_cast<int>(std::floor(ratio * SINC_RESOLUTION)); |
|
| 612 |
+ int step = this->reg.sampleIncrease > 1.0 ? static_cast<int>(SINC_RESOLUTION / this->reg.sampleIncrease) : SINC_RESOLUTION; |
|
| 613 |
+ int shift_adj = shift * step / SINC_RESOLUTION; |
|
| 614 |
+ for (; i >= -static_cast<int>(SINC_WIDTH - 1); --i) |
|
| 616 | 615 |
{
|
| 617 | 616 |
int pos = i * step; |
| 618 |
- kernel_sum += kernel[i + LANCZOS_WIDTH - 1] = this->lanczos_lut[std::abs(shift_adj - pos)]; |
|
| 617 |
+ kernel_sum += kernel[i + SINC_WIDTH - 1] = this->sinc_lut[std::abs(shift_adj - pos)]; |
|
| 619 | 618 |
} |
| 620 | 619 |
double sum = 0.0; |
| 621 |
- for (i = 0; i < static_cast<int>(LANCZOS_WIDTH * 2); ++i) |
|
| 622 |
- sum += data[i - static_cast<int>(LANCZOS_WIDTH) + 1] * kernel[i]; |
|
| 620 |
+ for (i = 0; i < static_cast<int>(SINC_WIDTH * 2); ++i) |
|
| 621 |
+ sum += data[i - static_cast<int>(SINC_WIDTH) + 1] * kernel[i]; |
|
| 623 | 622 |
return static_cast<int32_t>(sum / kernel_sum); |
| 624 | 623 |
} |
| 625 | 624 |
else if (this->ply->interpolation > INTERPOLATION_COSINE) |
| ... | ... |
@@ -721,22 +720,59 @@ void Channel::IncrementSample() |
| 721 | 720 |
{
|
| 722 | 721 |
double samplePosition = this->reg.samplePosition + this->reg.sampleIncrease; |
| 723 | 722 |
|
| 724 |
- if (this->reg.format != 3 && this->reg.samplePosition >= 0) |
|
| 723 |
+ if (this->reg.format != 3) |
|
| 725 | 724 |
{
|
| 726 |
- uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition); |
|
| 727 |
- uint32_t newloc = static_cast<uint32_t>(samplePosition); |
|
| 725 |
+ if (this->reg.samplePosition < 0 && samplePosition >= 0) |
|
| 726 |
+ {
|
|
| 727 |
+ this->ringBuffer.Clear(); |
|
| 728 |
+ this->ringBuffer.bufferPos += SINC_WIDTH + 1; |
|
| 729 |
+ auto preData = std::vector<int16_t>(SINC_WIDTH + 1, this->reg.source->dataptr[0]); |
|
| 730 |
+ this->ringBuffer.PushSamples(&preData[0], SINC_WIDTH + 1); |
|
| 731 |
+ if (this->reg.totalLength < SINC_WIDTH + 1) |
|
| 732 |
+ {
|
|
| 733 |
+ this->ringBuffer.PushSamples(&this->reg.source->dataptr[0], this->reg.totalLength); |
|
| 734 |
+ if (this->reg.repeatMode == 1) |
|
| 735 |
+ {
|
|
| 736 |
+ size_t samplesLeft = SINC_WIDTH + 1 - this->reg.totalLength; |
|
| 737 |
+ while (samplesLeft) |
|
| 738 |
+ {
|
|
| 739 |
+ size_t samplesToPush = std::min(samplesLeft, this->reg.length); |
|
| 740 |
+ this->ringBuffer.PushSamples(&this->reg.source->dataptr[this->reg.loopStart], samplesToPush); |
|
| 741 |
+ samplesLeft -= samplesToPush; |
|
| 742 |
+ } |
|
| 743 |
+ } |
|
| 744 |
+ } |
|
| 745 |
+ else |
|
| 746 |
+ this->ringBuffer.PushSamples(&this->reg.source->dataptr[0], SINC_WIDTH + 1); |
|
| 747 |
+ } |
|
| 748 |
+ if (this->reg.samplePosition >= 0) |
|
| 749 |
+ {
|
|
| 750 |
+ uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition) + SINC_WIDTH + 1; |
|
| 751 |
+ uint32_t newloc = static_cast<uint32_t>(samplePosition) + SINC_WIDTH + 1; |
|
| 728 | 752 |
|
| 729 |
- if (newloc >= this->reg.totalLength) |
|
| 730 |
- newloc -= this->reg.length; |
|
| 753 |
+ if (this->reg.repeatMode == 1) |
|
| 754 |
+ {
|
|
| 755 |
+ if (loc >= this->reg.totalLength) |
|
| 756 |
+ loc -= this->reg.length; |
|
| 757 |
+ if (newloc >= this->reg.totalLength) |
|
| 758 |
+ newloc -= this->reg.length; |
|
| 759 |
+ } |
|
| 731 | 760 |
|
| 732 |
- while (loc != newloc) |
|
| 733 |
- {
|
|
| 734 |
- this->sampleHistory[this->sampleHistoryPtr] = this->sampleHistory[this->sampleHistoryPtr + 32] = this->reg.source->dataptr[loc++]; |
|
| 761 |
+ while (loc != newloc) |
|
| 762 |
+ {
|
|
| 763 |
+ this->ringBuffer.NextSample(); |
|
| 735 | 764 |
|
| 736 |
- this->sampleHistoryPtr = (this->sampleHistoryPtr + 1) & 31; |
|
| 765 |
+ if (loc < this->reg.totalLength) |
|
| 766 |
+ this->ringBuffer.PushSample(this->reg.source->dataptr[loc++]); |
|
| 767 |
+ else |
|
| 768 |
+ {
|
|
| 769 |
+ ++loc; |
|
| 770 |
+ this->ringBuffer.PushSample(this->reg.source->dataptr[this->reg.totalLength - 1]); |
|
| 771 |
+ } |
|
| 737 | 772 |
|
| 738 |
- if (loc >= this->reg.totalLength) |
|
| 739 |
- loc -= this->reg.length; |
|
| 773 |
+ if (this->reg.repeatMode == 1 && loc >= this->reg.totalLength) |
|
| 774 |
+ loc -= this->reg.length; |
|
| 775 |
+ } |
|
| 740 | 776 |
} |
| 741 | 777 |
} |
| 742 | 778 |
|
| ... | ... |
@@ -753,9 +789,3 @@ void Channel::IncrementSample() |
| 753 | 789 |
this->Kill(); |
| 754 | 790 |
} |
| 755 | 791 |
} |
| 756 |
- |
|
| 757 |
-void Channel::clearHistory() |
|
| 758 |
-{
|
|
| 759 |
- this->sampleHistoryPtr = 0; |
|
| 760 |
- memset(this->sampleHistory, 0, sizeof(this->sampleHistory)); |
|
| 761 |
-} |
| ... | ... |
@@ -611,10 +611,11 @@ int32_t Channel::Interpolate() |
| 611 | 611 |
double kernel[LANCZOS_WIDTH * 2], kernel_sum = 0.0; |
| 612 | 612 |
int i = LANCZOS_WIDTH, shift = static_cast<int>(std::floor(ratio * LANCZOS_RESOLUTION)); |
| 613 | 613 |
int step = this->reg.sampleIncrease > 1.0 ? static_cast<int>(LANCZOS_RESOLUTION / this->reg.sampleIncrease) : LANCZOS_RESOLUTION; |
| 614 |
+ int shift_adj = shift * step / LANCZOS_RESOLUTION; |
|
| 614 | 615 |
for (; i >= -static_cast<int>(LANCZOS_WIDTH - 1); --i) |
| 615 | 616 |
{
|
| 616 | 617 |
int pos = i * step; |
| 617 |
- kernel_sum += kernel[i + LANCZOS_WIDTH - 1] = this->lanczos_lut[std::abs(shift - pos)]; |
|
| 618 |
+ kernel_sum += kernel[i + LANCZOS_WIDTH - 1] = this->lanczos_lut[std::abs(shift_adj - pos)]; |
|
| 618 | 619 |
} |
| 619 | 620 |
double sum = 0.0; |
| 620 | 621 |
for (i = 0; i < static_cast<int>(LANCZOS_WIDTH * 2); ++i) |
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2013-04-23 |
|
| 4 |
+ * Last modification on 2013-04-26 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -44,7 +44,7 @@ TempSndReg::TempSndReg() : CR(0), SOURCE(nullptr), TIMER(0), REPEAT_POINT(0), LE |
| 44 | 44 |
|
| 45 | 45 |
bool Channel::initializedLUTs = false; |
| 46 | 46 |
double Channel::cosine_lut[Channel::COSINE_RESOLUTION]; |
| 47 |
-double Channel::lanczos_lut[Channel::LANCZOS_SAMPLES]; |
|
| 47 |
+double Channel::lanczos_lut[Channel::LANCZOS_SAMPLES + 1]; |
|
| 48 | 48 |
|
| 49 | 49 |
#ifndef M_PI |
| 50 | 50 |
static const double M_PI = 3.14159265358979323846; |
| ... | ... |
@@ -65,7 +65,7 @@ Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0), |
| 65 | 65 |
for (unsigned i = 0; i < COSINE_RESOLUTION; ++i) |
| 66 | 66 |
this->cosine_lut[i] = (1.0 - std::cos((static_cast<double>(i) / COSINE_RESOLUTION) * M_PI)) * 0.5; |
| 67 | 67 |
double dx = static_cast<double>(LANCZOS_WIDTH) / LANCZOS_SAMPLES, x = 0.0; |
| 68 |
- for (unsigned i = 0; i < LANCZOS_SAMPLES; ++i, x += dx) |
|
| 68 |
+ for (unsigned i = 0; i <= LANCZOS_SAMPLES; ++i, x += dx) |
|
| 69 | 69 |
this->lanczos_lut[i] = std::abs(x) < LANCZOS_WIDTH ? sinc(x) * sinc(x / LANCZOS_WIDTH) : 0.0; |
| 70 | 70 |
this->initializedLUTs = true; |
| 71 | 71 |
} |
| ... | ... |
@@ -604,37 +604,48 @@ int32_t Channel::Interpolate() |
| 604 | 604 |
double ratio = this->reg.samplePosition; |
| 605 | 605 |
ratio -= static_cast<int32_t>(ratio); |
| 606 | 606 |
|
| 607 |
- const auto &data = &this->sampleHistory[this->sampleHistoryPtr + 5]; |
|
| 608 |
- int32_t a = data[0], b = data[1]; |
|
| 607 |
+ const auto &data = &this->sampleHistory[this->sampleHistoryPtr + 16]; |
|
| 609 | 608 |
|
| 610 |
- double c0, c1, c2, c3, c4, c5; |
|
| 611 |
- if (this->ply->interpolation > INTERPOLATION_COSINE) |
|
| 609 |
+ if (this->ply->interpolation == INTERPOLATION_LANCZOS) |
|
| 612 | 610 |
{
|
| 613 |
- int32_t c = data[2], z = data[-1]; |
|
| 611 |
+ double kernel[LANCZOS_WIDTH * 2], kernel_sum = 0.0; |
|
| 612 |
+ int i = LANCZOS_WIDTH, shift = static_cast<int>(std::floor(ratio * LANCZOS_RESOLUTION)); |
|
| 613 |
+ int step = this->reg.sampleIncrease > 1.0 ? static_cast<int>(LANCZOS_RESOLUTION / this->reg.sampleIncrease) : LANCZOS_RESOLUTION; |
|
| 614 |
+ for (; i >= -static_cast<int>(LANCZOS_WIDTH - 1); --i) |
|
| 615 |
+ {
|
|
| 616 |
+ int pos = i * step; |
|
| 617 |
+ kernel_sum += kernel[i + LANCZOS_WIDTH - 1] = this->lanczos_lut[std::abs(shift - pos)]; |
|
| 618 |
+ } |
|
| 619 |
+ double sum = 0.0; |
|
| 620 |
+ for (i = 0; i < static_cast<int>(LANCZOS_WIDTH * 2); ++i) |
|
| 621 |
+ sum += data[i - static_cast<int>(LANCZOS_WIDTH) + 1] * kernel[i]; |
|
| 622 |
+ return static_cast<int32_t>(sum / kernel_sum); |
|
| 623 |
+ } |
|
| 624 |
+ else if (this->ply->interpolation > INTERPOLATION_COSINE) |
|
| 625 |
+ {
|
|
| 626 |
+ double c0, c1, c2, c3, c4, c5; |
|
| 614 | 627 |
|
| 615 | 628 |
if (this->ply->interpolation > INTERPOLATION_4POINTBSPLINE) |
| 616 | 629 |
{
|
| 617 |
- int32_t d = data[3], y = data[-2]; |
|
| 618 |
- |
|
| 619 | 630 |
if (this->ply->interpolation == INTERPOLATION_6POINTBSPLINE) |
| 620 | 631 |
{
|
| 621 |
- double ym2py2 = y + c, ym1py1 = z + b; |
|
| 622 |
- double y2mym2 = c - y, y1mym1 = b - z; |
|
| 632 |
+ double ym2py2 = data[-2] + data[2], ym1py1 = data[-1] + data[1]; |
|
| 633 |
+ double y2mym2 = data[2] - data[-2], y1mym1 = data[1] - data[-1]; |
|
| 623 | 634 |
double sixthym1py1 = 1 / 6.0 * ym1py1; |
| 624 |
- c0 = 1 / 120.0 * ym2py2 + 13 / 60.0 * ym1py1 + 0.55 * a; |
|
| 635 |
+ c0 = 1 / 120.0 * ym2py2 + 13 / 60.0 * ym1py1 + 0.55 * data[0]; |
|
| 625 | 636 |
c1 = 1 / 24.0 * y2mym2 + 5 / 12.0 * y1mym1; |
| 626 |
- c2 = 1 / 12.0 * ym2py2 + sixthym1py1 - 0.5 * a; |
|
| 637 |
+ c2 = 1 / 12.0 * ym2py2 + sixthym1py1 - 0.5 * data[0]; |
|
| 627 | 638 |
c3 = 1 / 12.0 * y2mym2 - 1 / 6.0 * y1mym1; |
| 628 |
- c4 = 1 / 24.0 * ym2py2 - sixthym1py1 + 0.25 * a; |
|
| 629 |
- c5 = 1 / 120.0 * (d - y) + 1 / 24.0 * (z - c) + 1 / 12.0 * (b - a); |
|
| 639 |
+ c4 = 1 / 24.0 * ym2py2 - sixthym1py1 + 0.25 * data[0]; |
|
| 640 |
+ c5 = 1 / 120.0 * (data[3] - data[-2]) + 1 / 24.0 * (data[-1] - data[2]) + 1 / 12.0 * (data[1] - data[0]); |
|
| 630 | 641 |
return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
| 631 | 642 |
} |
| 632 |
- else if (this->ply->interpolation == INTERPOLATION_6POINTOSCULATING) |
|
| 643 |
+ else // INTERPOLATION_6POINTOSCULATING |
|
| 633 | 644 |
{
|
| 634 | 645 |
ratio -= 0.5; |
| 635 |
- double even1 = y + d, odd1 = y - d; |
|
| 636 |
- double even2 = z + c, odd2 = z - c; |
|
| 637 |
- double even3 = a + b, odd3 = a - b; |
|
| 646 |
+ double even1 = data[-2] + data[3], odd1 = data[-2] - data[3]; |
|
| 647 |
+ double even2 = data[-1] + data[2], odd2 = data[-1] - data[2]; |
|
| 648 |
+ double even3 = data[0] + data[1], odd3 = data[0] - data[1]; |
|
| 638 | 649 |
c0 = 0.01171875 * even1 - 0.09765625 * even2 + 0.5859375 * even3; |
| 639 | 650 |
c1 = 0.2109375 * odd2 - 281 / 192.0 * odd3 - 13 / 384.0 * odd1; |
| 640 | 651 |
c2 = 0.40625 * even2 - 17 / 48.0 * even3 - 5 / 96.0 * even1; |
| ... | ... |
@@ -643,34 +654,21 @@ int32_t Channel::Interpolate() |
| 643 | 654 |
c5 = 25 / 24.0 * odd2 - 25 / 12.0 * odd3 - 5 / 24.0 * odd1; |
| 644 | 655 |
return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
| 645 | 656 |
} |
| 646 |
- else // INTERPOLATION_6POINTLANCZOS |
|
| 647 |
- {
|
|
| 648 |
- double kernel[6], kernel_sum = 0.0; |
|
| 649 |
- int i = 3, shift = static_cast<int>(std::floor(ratio * LANCZOS_RESOLUTION)); |
|
| 650 |
- for (; i >= -2; --i) |
|
| 651 |
- {
|
|
| 652 |
- int pos = i * LANCZOS_RESOLUTION; |
|
| 653 |
- kernel_sum += kernel[i + 2] = this->lanczos_lut[std::abs(shift - pos)]; |
|
| 654 |
- } |
|
| 655 |
- for (i = 0; i < 6; ++i) |
|
| 656 |
- kernel[i] /= kernel_sum; |
|
| 657 |
- return static_cast<int32_t>(y * kernel[0] + z * kernel[1] + a * kernel[2] + b * kernel[3] + c * kernel[4] + d * kernel[5]); |
|
| 658 |
- } |
|
| 659 | 657 |
} |
| 660 | 658 |
else // INTERPOLATION_4POINTBSPLINE |
| 661 | 659 |
{
|
| 662 |
- double ym1py1 = z + b; |
|
| 663 |
- c0 = 1 / 6.0 * ym1py1 + 2 / 3.0 * a; |
|
| 664 |
- c1 = 0.5 * (b - z); |
|
| 665 |
- c2 = 0.5 * ym1py1 - a; |
|
| 666 |
- c3 = 0.5 * (a - b) + 1 / 6.0 * (c - z); |
|
| 660 |
+ double ym1py1 = data[-1] + data[1]; |
|
| 661 |
+ c0 = 1 / 6.0 * ym1py1 + 2 / 3.0 * data[0]; |
|
| 662 |
+ c1 = 0.5 * (data[1] - data[-1]); |
|
| 663 |
+ c2 = 0.5 * ym1py1 - data[0]; |
|
| 664 |
+ c3 = 0.5 * (data[0] - data[1]) + 1 / 6.0 * (data[2] - data[-1]); |
|
| 667 | 665 |
return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0); |
| 668 | 666 |
} |
| 669 | 667 |
} |
| 670 | 668 |
else if (this->ply->interpolation == INTERPOLATION_COSINE) |
| 671 |
- return static_cast<int32_t>(a + this->cosine_lut[static_cast<unsigned>(ratio * COSINE_RESOLUTION)] * (b - a)); |
|
| 669 |
+ return static_cast<int32_t>(data[0] + this->cosine_lut[static_cast<unsigned>(ratio * COSINE_RESOLUTION)] * (data[1] - data[0])); |
|
| 672 | 670 |
else // INTERPOLATION_LINEAR |
| 673 |
- return static_cast<int32_t>(a + ratio * (b - a)); |
|
| 671 |
+ return static_cast<int32_t>(data[0] + ratio * (data[1] - data[0])); |
|
| 674 | 672 |
} |
| 675 | 673 |
|
| 676 | 674 |
int32_t Channel::GenerateSample() |
| ... | ... |
@@ -732,9 +730,9 @@ void Channel::IncrementSample() |
| 732 | 730 |
|
| 733 | 731 |
while (loc != newloc) |
| 734 | 732 |
{
|
| 735 |
- this->sampleHistory[this->sampleHistoryPtr] = this->sampleHistory[this->sampleHistoryPtr + 8] = this->reg.source->dataptr[loc++]; |
|
| 733 |
+ this->sampleHistory[this->sampleHistoryPtr] = this->sampleHistory[this->sampleHistoryPtr + 32] = this->reg.source->dataptr[loc++]; |
|
| 736 | 734 |
|
| 737 |
- this->sampleHistoryPtr = (this->sampleHistoryPtr + 1) & 7; |
|
| 735 |
+ this->sampleHistoryPtr = (this->sampleHistoryPtr + 1) & 31; |
|
| 738 | 736 |
|
| 739 | 737 |
if (loc >= this->reg.totalLength) |
| 740 | 738 |
loc -= this->reg.length; |
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2013-04-18 |
|
| 4 |
+ * Last modification on 2013-04-23 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -11,8 +11,7 @@ |
| 11 | 11 |
* http://desmume.org/ |
| 12 | 12 |
*/ |
| 13 | 13 |
|
| 14 |
-#define _USE_MATH_DEFINES |
|
| 15 |
-#include <cmath> |
|
| 14 |
+#include "XSFCommon.h" |
|
| 16 | 15 |
#include "Channel.h" |
| 17 | 16 |
#include "Player.h" |
| 18 | 17 |
#include "common.h" |
| ... | ... |
@@ -43,11 +42,33 @@ TempSndReg::TempSndReg() : CR(0), SOURCE(nullptr), TIMER(0), REPEAT_POINT(0), LE |
| 43 | 42 |
{
|
| 44 | 43 |
} |
| 45 | 44 |
|
| 45 |
+bool Channel::initializedLUTs = false; |
|
| 46 |
+double Channel::cosine_lut[Channel::COSINE_RESOLUTION]; |
|
| 47 |
+double Channel::lanczos_lut[Channel::LANCZOS_SAMPLES]; |
|
| 48 |
+ |
|
| 49 |
+#ifndef M_PI |
|
| 50 |
+static const double M_PI = 3.14159265358979323846; |
|
| 51 |
+#endif |
|
| 52 |
+ |
|
| 53 |
+static inline double sinc(double x) |
|
| 54 |
+{
|
|
| 55 |
+ return fEqual(x, 0.0) ? 1.0 : std::sin(x * M_PI) / (x * M_PI); |
|
| 56 |
+} |
|
| 57 |
+ |
|
| 46 | 58 |
Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0), manualSweep(false), flags(), pan(0), extAmpl(0), velocity(0), extPan(0), |
| 47 | 59 |
key(0), ampl(0), extTune(0), orgKey(0), modType(0), modSpeed(0), modDepth(0), modRange(0), modDelay(0), modDelayCnt(0), modCounter(0), |
| 48 | 60 |
sweepLen(0), sweepCnt(0), sweepPitch(0), attackLvl(0), sustainLvl(0x7F), decayRate(0), releaseRate(0xFFFF), noteLength(-1), vol(0), ply(nullptr), reg() |
| 49 | 61 |
{
|
| 50 | 62 |
this->clearHistory(); |
| 63 |
+ if (!this->initializedLUTs) |
|
| 64 |
+ {
|
|
| 65 |
+ for (unsigned i = 0; i < COSINE_RESOLUTION; ++i) |
|
| 66 |
+ this->cosine_lut[i] = (1.0 - std::cos((static_cast<double>(i) / COSINE_RESOLUTION) * M_PI)) * 0.5; |
|
| 67 |
+ double dx = static_cast<double>(LANCZOS_WIDTH) / LANCZOS_SAMPLES, x = 0.0; |
|
| 68 |
+ for (unsigned i = 0; i < LANCZOS_SAMPLES; ++i, x += dx) |
|
| 69 |
+ this->lanczos_lut[i] = std::abs(x) < LANCZOS_WIDTH ? sinc(x) * sinc(x / LANCZOS_WIDTH) : 0.0; |
|
| 70 |
+ this->initializedLUTs = true; |
|
| 71 |
+ } |
|
| 51 | 72 |
} |
| 52 | 73 |
|
| 53 | 74 |
void Channel::UpdateVol(const Track &trk) |
| ... | ... |
@@ -575,10 +596,6 @@ static const int16_t wavedutytbl[8][8] = |
| 575 | 596 |
{ -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF }
|
| 576 | 597 |
}; |
| 577 | 598 |
|
| 578 |
-#ifndef M_PI |
|
| 579 |
-static const double M_PI = 3.14159265358979323846; |
|
| 580 |
-#endif |
|
| 581 |
- |
|
| 582 | 599 |
// Linear and Cosine interpolation code originally from DeSmuME |
| 583 | 600 |
// B-spline and Osculating come from Olli Niemitalo: |
| 584 | 601 |
// http://www.student.oulu.fi/~oniemita/dsp/deip.pdf |
| ... | ... |
@@ -612,7 +629,7 @@ int32_t Channel::Interpolate() |
| 612 | 629 |
c5 = 1 / 120.0 * (d - y) + 1 / 24.0 * (z - c) + 1 / 12.0 * (b - a); |
| 613 | 630 |
return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
| 614 | 631 |
} |
| 615 |
- else // INTERPOLATION_6POINTOSCULATING |
|
| 632 |
+ else if (this->ply->interpolation == INTERPOLATION_6POINTOSCULATING) |
|
| 616 | 633 |
{
|
| 617 | 634 |
ratio -= 0.5; |
| 618 | 635 |
double even1 = y + d, odd1 = y - d; |
| ... | ... |
@@ -626,6 +643,19 @@ int32_t Channel::Interpolate() |
| 626 | 643 |
c5 = 25 / 24.0 * odd2 - 25 / 12.0 * odd3 - 5 / 24.0 * odd1; |
| 627 | 644 |
return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
| 628 | 645 |
} |
| 646 |
+ else // INTERPOLATION_6POINTLANCZOS |
|
| 647 |
+ {
|
|
| 648 |
+ double kernel[6], kernel_sum = 0.0; |
|
| 649 |
+ int i = 3, shift = static_cast<int>(std::floor(ratio * LANCZOS_RESOLUTION)); |
|
| 650 |
+ for (; i >= -2; --i) |
|
| 651 |
+ {
|
|
| 652 |
+ int pos = i * LANCZOS_RESOLUTION; |
|
| 653 |
+ kernel_sum += kernel[i + 2] = this->lanczos_lut[std::abs(shift - pos)]; |
|
| 654 |
+ } |
|
| 655 |
+ for (i = 0; i < 6; ++i) |
|
| 656 |
+ kernel[i] /= kernel_sum; |
|
| 657 |
+ return static_cast<int32_t>(y * kernel[0] + z * kernel[1] + a * kernel[2] + b * kernel[3] + c * kernel[4] + d * kernel[5]); |
|
| 658 |
+ } |
|
| 629 | 659 |
} |
| 630 | 660 |
else // INTERPOLATION_4POINTBSPLINE |
| 631 | 661 |
{
|
| ... | ... |
@@ -638,10 +668,7 @@ int32_t Channel::Interpolate() |
| 638 | 668 |
} |
| 639 | 669 |
} |
| 640 | 670 |
else if (this->ply->interpolation == INTERPOLATION_COSINE) |
| 641 |
- {
|
|
| 642 |
- double ratio2 = (1.0 - std::cos(ratio * M_PI)) * 0.5; |
|
| 643 |
- return static_cast<int32_t>(a + ratio2 * (b - a)); |
|
| 644 |
- } |
|
| 671 |
+ return static_cast<int32_t>(a + this->cosine_lut[static_cast<unsigned>(ratio * COSINE_RESOLUTION)] * (b - a)); |
|
| 645 | 672 |
else // INTERPOLATION_LINEAR |
| 646 | 673 |
return static_cast<int32_t>(a + ratio * (b - a)); |
| 647 | 674 |
} |
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2013-04-12 |
|
| 4 |
+ * Last modification on 2013-04-18 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -47,6 +47,7 @@ Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0), |
| 47 | 47 |
key(0), ampl(0), extTune(0), orgKey(0), modType(0), modSpeed(0), modDepth(0), modRange(0), modDelay(0), modDelayCnt(0), modCounter(0), |
| 48 | 48 |
sweepLen(0), sweepCnt(0), sweepPitch(0), attackLvl(0), sustainLvl(0x7F), decayRate(0), releaseRate(0xFFFF), noteLength(-1), vol(0), ply(nullptr), reg() |
| 49 | 49 |
{
|
| 50 |
+ this->clearHistory(); |
|
| 50 | 51 |
} |
| 51 | 52 |
|
| 52 | 53 |
void Channel::UpdateVol(const Track &trk) |
| ... | ... |
@@ -122,6 +123,7 @@ void Channel::Kill() |
| 122 | 123 |
this->reg.ClearControlRegister(); |
| 123 | 124 |
this->vol = 0; |
| 124 | 125 |
this->noteLength = -1; |
| 126 |
+ this->clearHistory(); |
|
| 125 | 127 |
} |
| 126 | 128 |
|
| 127 | 129 |
static inline int getModFlag(int type) |
| ... | ... |
@@ -585,38 +587,17 @@ int32_t Channel::Interpolate() |
| 585 | 587 |
double ratio = this->reg.samplePosition; |
| 586 | 588 |
ratio -= static_cast<int32_t>(ratio); |
| 587 | 589 |
|
| 588 |
- uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition); |
|
| 589 |
- const auto &data = &this->reg.source->dataptr[loc]; |
|
| 590 |
- int32_t a = data[0], b; |
|
| 591 |
- if (loc + 1 < this->reg.totalLength) |
|
| 592 |
- b = data[1]; |
|
| 593 |
- else |
|
| 594 |
- b = a; |
|
| 590 |
+ const auto &data = &this->sampleHistory[this->sampleHistoryPtr + 5]; |
|
| 591 |
+ int32_t a = data[0], b = data[1]; |
|
| 595 | 592 |
|
| 596 | 593 |
double c0, c1, c2, c3, c4, c5; |
| 597 | 594 |
if (this->ply->interpolation > INTERPOLATION_COSINE) |
| 598 | 595 |
{
|
| 599 |
- int32_t c, z; |
|
| 600 |
- if (loc + 2 < this->reg.totalLength) |
|
| 601 |
- c = data[2]; |
|
| 602 |
- else |
|
| 603 |
- c = b; |
|
| 604 |
- if (loc) |
|
| 605 |
- z = data[-1]; |
|
| 606 |
- else |
|
| 607 |
- z = a; |
|
| 596 |
+ int32_t c = data[2], z = data[-1]; |
|
| 608 | 597 |
|
| 609 | 598 |
if (this->ply->interpolation > INTERPOLATION_4POINTBSPLINE) |
| 610 | 599 |
{
|
| 611 |
- int32_t d, y; |
|
| 612 |
- if (loc + 3 < this->reg.totalLength) |
|
| 613 |
- d = data[3]; |
|
| 614 |
- else |
|
| 615 |
- d = c; |
|
| 616 |
- if (loc > 1) |
|
| 617 |
- y = data[-2]; |
|
| 618 |
- else |
|
| 619 |
- y = z; |
|
| 600 |
+ int32_t d = data[3], y = data[-2]; |
|
| 620 | 601 |
|
| 621 | 602 |
if (this->ply->interpolation == INTERPOLATION_6POINTBSPLINE) |
| 622 | 603 |
{
|
| ... | ... |
@@ -631,7 +612,7 @@ int32_t Channel::Interpolate() |
| 631 | 612 |
c5 = 1 / 120.0 * (d - y) + 1 / 24.0 * (z - c) + 1 / 12.0 * (b - a); |
| 632 | 613 |
return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
| 633 | 614 |
} |
| 634 |
- else |
|
| 615 |
+ else // INTERPOLATION_6POINTOSCULATING |
|
| 635 | 616 |
{
|
| 636 | 617 |
ratio -= 0.5; |
| 637 | 618 |
double even1 = y + d, odd1 = y - d; |
| ... | ... |
@@ -646,7 +627,7 @@ int32_t Channel::Interpolate() |
| 646 | 627 |
return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
| 647 | 628 |
} |
| 648 | 629 |
} |
| 649 |
- else |
|
| 630 |
+ else // INTERPOLATION_4POINTBSPLINE |
|
| 650 | 631 |
{
|
| 651 | 632 |
double ym1py1 = z + b; |
| 652 | 633 |
c0 = 1 / 6.0 * ym1py1 + 2 / 3.0 * a; |
| ... | ... |
@@ -661,7 +642,7 @@ int32_t Channel::Interpolate() |
| 661 | 642 |
double ratio2 = (1.0 - std::cos(ratio * M_PI)) * 0.5; |
| 662 | 643 |
return static_cast<int32_t>(a + ratio2 * (b - a)); |
| 663 | 644 |
} |
| 664 |
- else |
|
| 645 |
+ else // INTERPOLATION_LINEAR |
|
| 665 | 646 |
return static_cast<int32_t>(a + ratio * (b - a)); |
| 666 | 647 |
} |
| 667 | 648 |
|
| ... | ... |
@@ -712,7 +693,29 @@ int32_t Channel::GenerateSample() |
| 712 | 693 |
|
| 713 | 694 |
void Channel::IncrementSample() |
| 714 | 695 |
{
|
| 715 |
- this->reg.samplePosition += this->reg.sampleIncrease; |
|
| 696 |
+ double samplePosition = this->reg.samplePosition + this->reg.sampleIncrease; |
|
| 697 |
+ |
|
| 698 |
+ if (this->reg.format != 3 && this->reg.samplePosition >= 0) |
|
| 699 |
+ {
|
|
| 700 |
+ uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition); |
|
| 701 |
+ uint32_t newloc = static_cast<uint32_t>(samplePosition); |
|
| 702 |
+ |
|
| 703 |
+ if (newloc >= this->reg.totalLength) |
|
| 704 |
+ newloc -= this->reg.length; |
|
| 705 |
+ |
|
| 706 |
+ while (loc != newloc) |
|
| 707 |
+ {
|
|
| 708 |
+ this->sampleHistory[this->sampleHistoryPtr] = this->sampleHistory[this->sampleHistoryPtr + 8] = this->reg.source->dataptr[loc++]; |
|
| 709 |
+ |
|
| 710 |
+ this->sampleHistoryPtr = (this->sampleHistoryPtr + 1) & 7; |
|
| 711 |
+ |
|
| 712 |
+ if (loc >= this->reg.totalLength) |
|
| 713 |
+ loc -= this->reg.length; |
|
| 714 |
+ } |
|
| 715 |
+ } |
|
| 716 |
+ |
|
| 717 |
+ this->reg.samplePosition = samplePosition; |
|
| 718 |
+ |
|
| 716 | 719 |
if (this->reg.format != 3 && this->reg.samplePosition >= this->reg.totalLength) |
| 717 | 720 |
{
|
| 718 | 721 |
if (this->reg.repeatMode == 1) |
| ... | ... |
@@ -724,3 +727,9 @@ void Channel::IncrementSample() |
| 724 | 727 |
this->Kill(); |
| 725 | 728 |
} |
| 726 | 729 |
} |
| 730 |
+ |
|
| 731 |
+void Channel::clearHistory() |
|
| 732 |
+{
|
|
| 733 |
+ this->sampleHistoryPtr = 0; |
|
| 734 |
+ memset(this->sampleHistory, 0, sizeof(this->sampleHistory)); |
|
| 735 |
+} |
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2013-04-10 |
|
| 4 |
+ * Last modification on 2013-04-12 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -578,7 +578,7 @@ static const double M_PI = 3.14159265358979323846; |
| 578 | 578 |
#endif |
| 579 | 579 |
|
| 580 | 580 |
// Linear and Cosine interpolation code originally from DeSmuME |
| 581 |
-// B-spline, Hermite, and Optimal come from Olli Niemitalo: |
|
| 581 |
+// B-spline and Osculating come from Olli Niemitalo: |
|
| 582 | 582 |
// http://www.student.oulu.fi/~oniemita/dsp/deip.pdf |
| 583 | 583 |
int32_t Channel::Interpolate() |
| 584 | 584 |
{
|
| ... | ... |
@@ -594,56 +594,31 @@ int32_t Channel::Interpolate() |
| 594 | 594 |
b = a; |
| 595 | 595 |
|
| 596 | 596 |
double c0, c1, c2, c3, c4, c5; |
| 597 |
- if (this->ply->interpolation > INTERPOLATION_2POINTOPTIMAL) |
|
| 597 |
+ if (this->ply->interpolation > INTERPOLATION_COSINE) |
|
| 598 | 598 |
{
|
| 599 | 599 |
int32_t c, z; |
| 600 | 600 |
if (loc + 2 < this->reg.totalLength) |
| 601 | 601 |
c = data[2]; |
| 602 | 602 |
else |
| 603 |
- c = a; |
|
| 603 |
+ c = b; |
|
| 604 | 604 |
if (loc) |
| 605 | 605 |
z = data[-1]; |
| 606 | 606 |
else |
| 607 | 607 |
z = a; |
| 608 | 608 |
|
| 609 |
- if (this->ply->interpolation > INTERPOLATION_4POINTOPTIMAL) |
|
| 609 |
+ if (this->ply->interpolation > INTERPOLATION_4POINTBSPLINE) |
|
| 610 | 610 |
{
|
| 611 | 611 |
int32_t d, y; |
| 612 | 612 |
if (loc + 3 < this->reg.totalLength) |
| 613 | 613 |
d = data[3]; |
| 614 | 614 |
else |
| 615 |
- d = a; |
|
| 615 |
+ d = c; |
|
| 616 | 616 |
if (loc > 1) |
| 617 | 617 |
y = data[-2]; |
| 618 | 618 |
else |
| 619 |
- y = a; |
|
| 619 |
+ y = z; |
|
| 620 | 620 |
|
| 621 |
- if (this->ply->interpolation == INTERPOLATION_6POINTHERMITE) |
|
| 622 |
- {
|
|
| 623 |
- double eighthym2 = 0.125 * y; |
|
| 624 |
- double eleventwentyfourthy2 = 11 / 24.0 * c; |
|
| 625 |
- double twelfthy3 = 1 / 12.0 * d; |
|
| 626 |
- c0 = a; |
|
| 627 |
- c1 = 1 / 12.0 * (y - c) + 2 / 3.0 * (b - z); |
|
| 628 |
- c2 = 13 / 12.0 * z - 25 / 12.0 * a + 1.5 * b - eleventwentyfourthy2 + twelfthy3 - eighthym2; |
|
| 629 |
- c3 = 5 / 12.0 * a - 7 / 12.0 * b + 7 / 24.0 * c - 1 / 24.0 * (y + z + d); |
|
| 630 |
- c4 = eighthym2 - 7 / 12.0 * z + 13 / 12.0 * a - b + eleventwentyfourthy2 - twelfthy3; |
|
| 631 |
- c5 = 1 / 24.0 * (d - y) + 5 / 24.0 * (z - c) + 5 / 12.0 * (b - a); |
|
| 632 |
- return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 633 |
- } |
|
| 634 |
- else if (this->ply->interpolation == INTERPOLATION_6POINTLAGRANGE) |
|
| 635 |
- {
|
|
| 636 |
- float ym1py1 = z + b; |
|
| 637 |
- float twentyfourthym2py2 = 1 / 24.0 * (y + c); |
|
| 638 |
- float c0 = a; |
|
| 639 |
- float c1 = 1 / 20.0 * y - 0.5 * z - 1 / 3.0 * a + b - 0.25 * c + 1 / 30.0 * d; |
|
| 640 |
- float c2 = 2 / 3.0 * ym1py1 - 1.25 * a - twentyfourthym2py2; |
|
| 641 |
- float c3 = 5 / 12.0 * a - 7 / 12.0 * b + 7 / 24.0 * c - 1 / 24.0 * (y + z + d); |
|
| 642 |
- float c4 = 0.25 * a - 1 / 6.0 * ym1py1 + twentyfourthym2py2; |
|
| 643 |
- float c5 = 1 / 120.0 * (d - y) + 1 / 24.0 * (z - c) + 1 / 12.0 * (b - a); |
|
| 644 |
- return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 645 |
- } |
|
| 646 |
- else if (this->ply->interpolation == INTERPOLATION_6POINTBSPLINE) |
|
| 621 |
+ if (this->ply->interpolation == INTERPOLATION_6POINTBSPLINE) |
|
| 647 | 622 |
{
|
| 648 | 623 |
double ym2py2 = y + c, ym1py1 = z + b; |
| 649 | 624 |
double y2mym2 = c - y, y1mym1 = b - z; |
| ... | ... |
@@ -659,65 +634,27 @@ int32_t Channel::Interpolate() |
| 659 | 634 |
else |
| 660 | 635 |
{
|
| 661 | 636 |
ratio -= 0.5; |
| 662 |
- double even1 = b + a, odd1 = b - a; |
|
| 663 |
- double even2 = c + z, odd2 = c - z; |
|
| 664 |
- double even3 = d + y, odd3 = d - y; |
|
| 665 |
- c0 = even1 * 0.41809989254549901 + even2 * 0.08049339946273310 + even3 * 0.00140670799165932; |
|
| 666 |
- c1 = odd1 * 0.32767596257424964 + odd2 * 0.20978189376640677 + odd3 * 0.00859567104974701; |
|
| 667 |
- c2 = even1 * -0.206944618112960001 + even2 * 0.18541689550861262 + even3 * 0.02152772260740132; |
|
| 668 |
- c3 = odd1 * -0.21686095413034051 + odd2 * 0.02509557922091643 + odd3 * 0.02831484751363800; |
|
| 669 |
- c4 = even1 * 0.04163046817137675 + even2 * -0.06244556931623735 + even3 * 0.02081510113314315; |
|
| 670 |
- c5 = odd1 * 0.07990500783668089 + odd2 * -0.03994519162531633 + odd3 * 0.00798609327859495; |
|
| 637 |
+ double even1 = y + d, odd1 = y - d; |
|
| 638 |
+ double even2 = z + c, odd2 = z - c; |
|
| 639 |
+ double even3 = a + b, odd3 = a - b; |
|
| 640 |
+ c0 = 0.01171875 * even1 - 0.09765625 * even2 + 0.5859375 * even3; |
|
| 641 |
+ c1 = 0.2109375 * odd2 - 281 / 192.0 * odd3 - 13 / 384.0 * odd1; |
|
| 642 |
+ c2 = 0.40625 * even2 - 17 / 48.0 * even3 - 5 / 96.0 * even1; |
|
| 643 |
+ c3 = 0.1875 * odd1 - 53 / 48.0 * odd2 + 2.375 * odd3; |
|
| 644 |
+ c4 = 1 / 48.0 * even1 - 0.0625 * even2 + 1 / 24.0 * even3; |
|
| 645 |
+ c5 = 25 / 24.0 * odd2 - 25 / 12.0 * odd3 - 5 / 24.0 * odd1; |
|
| 671 | 646 |
return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
| 672 | 647 |
} |
| 673 | 648 |
} |
| 674 |
- else if (this->ply->interpolation == INTERPOLATION_4POINTHERMITE) |
|
| 675 |
- {
|
|
| 676 |
- c0 = a; |
|
| 677 |
- c1 = 0.5 * (b - z); |
|
| 678 |
- c2 = z - 2.5 * a + 2 * b - 0.5 * c; |
|
| 679 |
- c3 = 0.5 * (c - z) + 1.5 * (a - b); |
|
| 680 |
- return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 681 |
- } |
|
| 682 |
- else if (this->ply->interpolation == INTERPOLATION_4POINTLAGRANGE) |
|
| 683 |
- {
|
|
| 684 |
- float c0 = a; |
|
| 685 |
- float c1 = b - 1 / 3.0 * z - 0.5 * a - 1 / 6.0 * c; |
|
| 686 |
- float c2 = 0.5 * (z + b) - a; |
|
| 687 |
- float c3 = 1 / 6.0 * (c - z) + 0.5 * (a - b); |
|
| 688 |
- return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 689 |
- } |
|
| 690 |
- else if (this->ply->interpolation == INTERPOLATION_4POINTBSPLINE) |
|
| 649 |
+ else |
|
| 691 | 650 |
{
|
| 692 |
- double zpb = z + b; |
|
| 693 |
- c0 = 1 / 6.0 * zpb + 2 / 3.0 * a; |
|
| 651 |
+ double ym1py1 = z + b; |
|
| 652 |
+ c0 = 1 / 6.0 * ym1py1 + 2 / 3.0 * a; |
|
| 694 | 653 |
c1 = 0.5 * (b - z); |
| 695 |
- c2 = 0.5 * zpb - a; |
|
| 654 |
+ c2 = 0.5 * ym1py1 - a; |
|
| 696 | 655 |
c3 = 0.5 * (a - b) + 1 / 6.0 * (c - z); |
| 697 | 656 |
return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0); |
| 698 | 657 |
} |
| 699 |
- else |
|
| 700 |
- {
|
|
| 701 |
- ratio -= 0.5; |
|
| 702 |
- double even1 = b + a, odd1 = b - a; |
|
| 703 |
- double even2 = c + z, odd2 = c - z; |
|
| 704 |
- c0 = even1 * 0.46822774170144532 + even2 * 0.03177225758005808; |
|
| 705 |
- c1 = odd1 * 0.55890365706150436 + odd2 * 0.14703258836343669; |
|
| 706 |
- c2 = even1 * -0.250153411893796031 + even2 * 0.25015343462990891; |
|
| 707 |
- c3 = odd1 * -0.49800710906733769 + odd2 * 0.16600005174304033; |
|
| 708 |
- c4 = even1 * 0.00064264050033187 + even2 * -0.00064273459469381; |
|
| 709 |
- return static_cast<int32_t>((((c4 * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 710 |
- } |
|
| 711 |
- } |
|
| 712 |
- else if (this->ply->interpolation == INTERPOLATION_2POINTOPTIMAL) |
|
| 713 |
- {
|
|
| 714 |
- ratio -= 0.5; |
|
| 715 |
- double even1 = b + a, odd1 = b - a; |
|
| 716 |
- c0 = even1 * 0.50001096675880796; |
|
| 717 |
- c1 = odd1 * 1.03585606328743830; |
|
| 718 |
- c2 = even1 * -0.000131601105693441; |
|
| 719 |
- c3 = odd1 * -0.38606621963374965; |
|
| 720 |
- return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 721 | 658 |
} |
| 722 | 659 |
else if (this->ply->interpolation == INTERPOLATION_COSINE) |
| 723 | 660 |
{
|
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2013-04-02 |
|
| 4 |
+ * Last modification on 2013-04-10 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -586,66 +586,114 @@ int32_t Channel::Interpolate() |
| 586 | 586 |
ratio -= static_cast<int32_t>(ratio); |
| 587 | 587 |
|
| 588 | 588 |
uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition); |
| 589 |
- const auto &data = &this->reg.source->data[loc]; |
|
| 589 |
+ const auto &data = &this->reg.source->dataptr[loc]; |
|
| 590 | 590 |
int32_t a = data[0], b; |
| 591 | 591 |
if (loc + 1 < this->reg.totalLength) |
| 592 | 592 |
b = data[1]; |
| 593 | 593 |
else |
| 594 |
- {
|
|
| 595 |
- if (loc) |
|
| 596 |
- {
|
|
| 597 |
- int32_t am1 = data[-1]; |
|
| 598 |
- b = 2 * a - am1; |
|
| 599 |
- } |
|
| 600 |
- else |
|
| 601 |
- b = a; |
|
| 602 |
- } |
|
| 594 |
+ b = a; |
|
| 603 | 595 |
|
| 604 |
- if (this->ply->interpolation == INTERPOLATION_BSPLINE || this->ply->interpolation == INTERPOLATION_HERMITE || this->ply->interpolation == INTERPOLATION_OPTIMAL) |
|
| 596 |
+ double c0, c1, c2, c3, c4, c5; |
|
| 597 |
+ if (this->ply->interpolation > INTERPOLATION_2POINTOPTIMAL) |
|
| 605 | 598 |
{
|
| 606 | 599 |
int32_t c, z; |
| 607 | 600 |
if (loc + 2 < this->reg.totalLength) |
| 608 | 601 |
c = data[2]; |
| 609 | 602 |
else |
| 610 |
- {
|
|
| 611 |
- if (loc) |
|
| 612 |
- {
|
|
| 613 |
- int32_t am1 = data[-1]; |
|
| 614 |
- c = 3 * a - 2 * am1; |
|
| 615 |
- } |
|
| 616 |
- else |
|
| 617 |
- c = a; |
|
| 618 |
- } |
|
| 603 |
+ c = a; |
|
| 619 | 604 |
if (loc) |
| 620 | 605 |
z = data[-1]; |
| 621 | 606 |
else |
| 607 |
+ z = a; |
|
| 608 |
+ |
|
| 609 |
+ if (this->ply->interpolation > INTERPOLATION_4POINTOPTIMAL) |
|
| 622 | 610 |
{
|
| 623 |
- if (loc + 1 < this->reg.totalLength) |
|
| 611 |
+ int32_t d, y; |
|
| 612 |
+ if (loc + 3 < this->reg.totalLength) |
|
| 613 |
+ d = data[3]; |
|
| 614 |
+ else |
|
| 615 |
+ d = a; |
|
| 616 |
+ if (loc > 1) |
|
| 617 |
+ y = data[-2]; |
|
| 618 |
+ else |
|
| 619 |
+ y = a; |
|
| 620 |
+ |
|
| 621 |
+ if (this->ply->interpolation == INTERPOLATION_6POINTHERMITE) |
|
| 622 |
+ {
|
|
| 623 |
+ double eighthym2 = 0.125 * y; |
|
| 624 |
+ double eleventwentyfourthy2 = 11 / 24.0 * c; |
|
| 625 |
+ double twelfthy3 = 1 / 12.0 * d; |
|
| 626 |
+ c0 = a; |
|
| 627 |
+ c1 = 1 / 12.0 * (y - c) + 2 / 3.0 * (b - z); |
|
| 628 |
+ c2 = 13 / 12.0 * z - 25 / 12.0 * a + 1.5 * b - eleventwentyfourthy2 + twelfthy3 - eighthym2; |
|
| 629 |
+ c3 = 5 / 12.0 * a - 7 / 12.0 * b + 7 / 24.0 * c - 1 / 24.0 * (y + z + d); |
|
| 630 |
+ c4 = eighthym2 - 7 / 12.0 * z + 13 / 12.0 * a - b + eleventwentyfourthy2 - twelfthy3; |
|
| 631 |
+ c5 = 1 / 24.0 * (d - y) + 5 / 24.0 * (z - c) + 5 / 12.0 * (b - a); |
|
| 632 |
+ return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 633 |
+ } |
|
| 634 |
+ else if (this->ply->interpolation == INTERPOLATION_6POINTLAGRANGE) |
|
| 635 |
+ {
|
|
| 636 |
+ float ym1py1 = z + b; |
|
| 637 |
+ float twentyfourthym2py2 = 1 / 24.0 * (y + c); |
|
| 638 |
+ float c0 = a; |
|
| 639 |
+ float c1 = 1 / 20.0 * y - 0.5 * z - 1 / 3.0 * a + b - 0.25 * c + 1 / 30.0 * d; |
|
| 640 |
+ float c2 = 2 / 3.0 * ym1py1 - 1.25 * a - twentyfourthym2py2; |
|
| 641 |
+ float c3 = 5 / 12.0 * a - 7 / 12.0 * b + 7 / 24.0 * c - 1 / 24.0 * (y + z + d); |
|
| 642 |
+ float c4 = 0.25 * a - 1 / 6.0 * ym1py1 + twentyfourthym2py2; |
|
| 643 |
+ float c5 = 1 / 120.0 * (d - y) + 1 / 24.0 * (z - c) + 1 / 12.0 * (b - a); |
|
| 644 |
+ return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 645 |
+ } |
|
| 646 |
+ else if (this->ply->interpolation == INTERPOLATION_6POINTBSPLINE) |
|
| 624 | 647 |
{
|
| 625 |
- int32_t ap1 = data[1]; |
|
| 626 |
- z = 2 * a - ap1; |
|
| 648 |
+ double ym2py2 = y + c, ym1py1 = z + b; |
|
| 649 |
+ double y2mym2 = c - y, y1mym1 = b - z; |
|
| 650 |
+ double sixthym1py1 = 1 / 6.0 * ym1py1; |
|
| 651 |
+ c0 = 1 / 120.0 * ym2py2 + 13 / 60.0 * ym1py1 + 0.55 * a; |
|
| 652 |
+ c1 = 1 / 24.0 * y2mym2 + 5 / 12.0 * y1mym1; |
|
| 653 |
+ c2 = 1 / 12.0 * ym2py2 + sixthym1py1 - 0.5 * a; |
|
| 654 |
+ c3 = 1 / 12.0 * y2mym2 - 1 / 6.0 * y1mym1; |
|
| 655 |
+ c4 = 1 / 24.0 * ym2py2 - sixthym1py1 + 0.25 * a; |
|
| 656 |
+ c5 = 1 / 120.0 * (d - y) + 1 / 24.0 * (z - c) + 1 / 12.0 * (b - a); |
|
| 657 |
+ return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 627 | 658 |
} |
| 628 | 659 |
else |
| 629 |
- z = a; |
|
| 660 |
+ {
|
|
| 661 |
+ ratio -= 0.5; |
|
| 662 |
+ double even1 = b + a, odd1 = b - a; |
|
| 663 |
+ double even2 = c + z, odd2 = c - z; |
|
| 664 |
+ double even3 = d + y, odd3 = d - y; |
|
| 665 |
+ c0 = even1 * 0.41809989254549901 + even2 * 0.08049339946273310 + even3 * 0.00140670799165932; |
|
| 666 |
+ c1 = odd1 * 0.32767596257424964 + odd2 * 0.20978189376640677 + odd3 * 0.00859567104974701; |
|
| 667 |
+ c2 = even1 * -0.206944618112960001 + even2 * 0.18541689550861262 + even3 * 0.02152772260740132; |
|
| 668 |
+ c3 = odd1 * -0.21686095413034051 + odd2 * 0.02509557922091643 + odd3 * 0.02831484751363800; |
|
| 669 |
+ c4 = even1 * 0.04163046817137675 + even2 * -0.06244556931623735 + even3 * 0.02081510113314315; |
|
| 670 |
+ c5 = odd1 * 0.07990500783668089 + odd2 * -0.03994519162531633 + odd3 * 0.00798609327859495; |
|
| 671 |
+ return static_cast<int32_t>(((((c5 * ratio + c4) * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 672 |
+ } |
|
| 630 | 673 |
} |
| 631 |
- |
|
| 632 |
- double c0, c1, c2, c3; |
|
| 633 |
- |
|
| 634 |
- if (this->ply->interpolation == INTERPOLATION_BSPLINE) |
|
| 674 |
+ else if (this->ply->interpolation == INTERPOLATION_4POINTHERMITE) |
|
| 635 | 675 |
{
|
| 636 |
- double zpb = z + b; |
|
| 637 |
- c0 = 1 / 6.0 * zpb + 2 / 3.0 * a; |
|
| 676 |
+ c0 = a; |
|
| 638 | 677 |
c1 = 0.5 * (b - z); |
| 639 |
- c2 = 0.5 * zpb - a; |
|
| 640 |
- c3 = 0.5 * (a - b) + 1 / 6.0 * (c - z); |
|
| 678 |
+ c2 = z - 2.5 * a + 2 * b - 0.5 * c; |
|
| 679 |
+ c3 = 0.5 * (c - z) + 1.5 * (a - b); |
|
| 641 | 680 |
return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0); |
| 642 | 681 |
} |
| 643 |
- else if (this->ply->interpolation == INTERPOLATION_HERMITE) |
|
| 682 |
+ else if (this->ply->interpolation == INTERPOLATION_4POINTLAGRANGE) |
|
| 644 | 683 |
{
|
| 645 |
- c0 = a; |
|
| 684 |
+ float c0 = a; |
|
| 685 |
+ float c1 = b - 1 / 3.0 * z - 0.5 * a - 1 / 6.0 * c; |
|
| 686 |
+ float c2 = 0.5 * (z + b) - a; |
|
| 687 |
+ float c3 = 1 / 6.0 * (c - z) + 0.5 * (a - b); |
|
| 688 |
+ return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 689 |
+ } |
|
| 690 |
+ else if (this->ply->interpolation == INTERPOLATION_4POINTBSPLINE) |
|
| 691 |
+ {
|
|
| 692 |
+ double zpb = z + b; |
|
| 693 |
+ c0 = 1 / 6.0 * zpb + 2 / 3.0 * a; |
|
| 646 | 694 |
c1 = 0.5 * (b - z); |
| 647 |
- c2 = z - 2.5 * a + 2 * b - 0.5 * c; |
|
| 648 |
- c3 = 0.5 * (c - z) + 1.5 * (a - b); |
|
| 695 |
+ c2 = 0.5 * zpb - a; |
|
| 696 |
+ c3 = 0.5 * (a - b) + 1 / 6.0 * (c - z); |
|
| 649 | 697 |
return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0); |
| 650 | 698 |
} |
| 651 | 699 |
else |
| ... | ... |
@@ -653,14 +701,24 @@ int32_t Channel::Interpolate() |
| 653 | 701 |
ratio -= 0.5; |
| 654 | 702 |
double even1 = b + a, odd1 = b - a; |
| 655 | 703 |
double even2 = c + z, odd2 = c - z; |
| 656 |
- c0 = even1 * 0.46835497211269561 + even2 * 0.03164502784253309; |
|
| 657 |
- c1 = odd1 * 0.56001293337091440 + odd2 * 0.14666238593949288; |
|
| 658 |
- c2 = even1 * -0.250038759826233691 + even2 * 0.25003876124297131; |
|
| 659 |
- c3 = odd1 * -0.49949850957839148 + odd2 * 0.16649935475113800; |
|
| 660 |
- double c4 = even1 * 0.00016095224137360 + even2 * -0.00016095810460478; |
|
| 704 |
+ c0 = even1 * 0.46822774170144532 + even2 * 0.03177225758005808; |
|
| 705 |
+ c1 = odd1 * 0.55890365706150436 + odd2 * 0.14703258836343669; |
|
| 706 |
+ c2 = even1 * -0.250153411893796031 + even2 * 0.25015343462990891; |
|
| 707 |
+ c3 = odd1 * -0.49800710906733769 + odd2 * 0.16600005174304033; |
|
| 708 |
+ c4 = even1 * 0.00064264050033187 + even2 * -0.00064273459469381; |
|
| 661 | 709 |
return static_cast<int32_t>((((c4 * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
| 662 | 710 |
} |
| 663 | 711 |
} |
| 712 |
+ else if (this->ply->interpolation == INTERPOLATION_2POINTOPTIMAL) |
|
| 713 |
+ {
|
|
| 714 |
+ ratio -= 0.5; |
|
| 715 |
+ double even1 = b + a, odd1 = b - a; |
|
| 716 |
+ c0 = even1 * 0.50001096675880796; |
|
| 717 |
+ c1 = odd1 * 1.03585606328743830; |
|
| 718 |
+ c2 = even1 * -0.000131601105693441; |
|
| 719 |
+ c3 = odd1 * -0.38606621963374965; |
|
| 720 |
+ return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 721 |
+ } |
|
| 664 | 722 |
else if (this->ply->interpolation == INTERPOLATION_COSINE) |
| 665 | 723 |
{
|
| 666 | 724 |
double ratio2 = (1.0 - std::cos(ratio * M_PI)) * 0.5; |
| ... | ... |
@@ -678,7 +736,7 @@ int32_t Channel::GenerateSample() |
| 678 | 736 |
if (this->reg.format != 3) |
| 679 | 737 |
{
|
| 680 | 738 |
if (this->ply->interpolation == INTERPOLATION_NONE) |
| 681 |
- return this->reg.source->data[static_cast<uint32_t>(this->reg.samplePosition)]; |
|
| 739 |
+ return this->reg.source->dataptr[static_cast<uint32_t>(this->reg.samplePosition)]; |
|
| 682 | 740 |
else |
| 683 | 741 |
return this->Interpolate(); |
| 684 | 742 |
} |
| ... | ... |
@@ -18,7 +18,7 @@ |
| 18 | 18 |
#include "common.h" |
| 19 | 19 |
|
| 20 | 20 |
NDSSoundRegister::NDSSoundRegister() : volumeMul(0), volumeDiv(0), panning(0), waveDuty(0), repeatMode(0), format(0), enable(false), |
| 21 |
- source(nullptr), timer(0), psgX(0), psgLast(0), psgLastCount(0), samplePosition(0), sampleIncrease(0), loopStart(0), length(0) |
|
| 21 |
+ source(nullptr), timer(0), psgX(0), psgLast(0), psgLastCount(0), samplePosition(0), sampleIncrease(0), loopStart(0), length(0), totalLength(0) |
|
| 22 | 22 |
{
|
| 23 | 23 |
} |
| 24 | 24 |
|
| ... | ... |
@@ -418,6 +418,7 @@ void Channel::Update() |
| 418 | 418 |
this->reg.source = this->tempReg.SOURCE; |
| 419 | 419 |
this->reg.loopStart = this->tempReg.REPEAT_POINT; |
| 420 | 420 |
this->reg.length = this->tempReg.LENGTH; |
| 421 |
+ this->reg.totalLength = this->reg.loopStart + this->reg.length; |
|
| 421 | 422 |
this->ampl = AMPL_THRESHOLD; |
| 422 | 423 |
this->state = CS_ATTACK; |
| 423 | 424 |
// Fall down |
| ... | ... |
@@ -587,7 +588,7 @@ int32_t Channel::Interpolate() |
| 587 | 588 |
uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition); |
| 588 | 589 |
const auto &data = &this->reg.source->data[loc]; |
| 589 | 590 |
int32_t a = data[0], b; |
| 590 |
- if (loc + 1 < this->reg.loopStart + this->reg.length) |
|
| 591 |
+ if (loc + 1 < this->reg.totalLength) |
|
| 591 | 592 |
b = data[1]; |
| 592 | 593 |
else |
| 593 | 594 |
{
|
| ... | ... |
@@ -603,7 +604,7 @@ int32_t Channel::Interpolate() |
| 603 | 604 |
if (this->ply->interpolation == INTERPOLATION_BSPLINE || this->ply->interpolation == INTERPOLATION_HERMITE || this->ply->interpolation == INTERPOLATION_OPTIMAL) |
| 604 | 605 |
{
|
| 605 | 606 |
int32_t c, z; |
| 606 |
- if (loc + 2 < this->reg.loopStart + this->reg.length) |
|
| 607 |
+ if (loc + 2 < this->reg.totalLength) |
|
| 607 | 608 |
c = data[2]; |
| 608 | 609 |
else |
| 609 | 610 |
{
|
| ... | ... |
@@ -619,7 +620,7 @@ int32_t Channel::Interpolate() |
| 619 | 620 |
z = data[-1]; |
| 620 | 621 |
else |
| 621 | 622 |
{
|
| 622 |
- if (loc + 1 < this->reg.loopStart + this->reg.length) |
|
| 623 |
+ if (loc + 1 < this->reg.totalLength) |
|
| 623 | 624 |
{
|
| 624 | 625 |
int32_t ap1 = data[1]; |
| 625 | 626 |
z = 2 * a - ap1; |
| ... | ... |
@@ -639,7 +640,7 @@ int32_t Channel::Interpolate() |
| 639 | 640 |
c3 = 0.5 * (a - b) + 1 / 6.0 * (c - z); |
| 640 | 641 |
return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0); |
| 641 | 642 |
} |
| 642 |
- if (this->ply->interpolation == INTERPOLATION_HERMITE) |
|
| 643 |
+ else if (this->ply->interpolation == INTERPOLATION_HERMITE) |
|
| 643 | 644 |
{
|
| 644 | 645 |
c0 = a; |
| 645 | 646 |
c1 = 0.5 * (b - z); |
| ... | ... |
@@ -717,11 +718,11 @@ int32_t Channel::GenerateSample() |
| 717 | 718 |
void Channel::IncrementSample() |
| 718 | 719 |
{
|
| 719 | 720 |
this->reg.samplePosition += this->reg.sampleIncrease; |
| 720 |
- if (this->reg.format != 3 && this->reg.samplePosition >= (this->reg.loopStart + this->reg.length)) |
|
| 721 |
+ if (this->reg.format != 3 && this->reg.samplePosition >= this->reg.totalLength) |
|
| 721 | 722 |
{
|
| 722 | 723 |
if (this->reg.repeatMode == 1) |
| 723 | 724 |
{
|
| 724 |
- while (this->reg.samplePosition >= (this->reg.loopStart + this->reg.length)) |
|
| 725 |
+ while (this->reg.samplePosition >= this->reg.totalLength) |
|
| 725 | 726 |
this->reg.samplePosition -= this->reg.length; |
| 726 | 727 |
} |
| 727 | 728 |
else |
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2013-03-30 |
|
| 4 |
+ * Last modification on 2013-04-02 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -576,17 +576,97 @@ static const int16_t wavedutytbl[8][8] = |
| 576 | 576 |
static const double M_PI = 3.14159265358979323846; |
| 577 | 577 |
#endif |
| 578 | 578 |
|
| 579 |
-int32_t Channel::Interpolate(int32_t a, int32_t b, double ratio) |
|
| 579 |
+// Linear and Cosine interpolation code originally from DeSmuME |
|
| 580 |
+// B-spline, Hermite, and Optimal come from Olli Niemitalo: |
|
| 581 |
+// http://www.student.oulu.fi/~oniemita/dsp/deip.pdf |
|
| 582 |
+int32_t Channel::Interpolate() |
|
| 580 | 583 |
{
|
| 581 |
- float ratiof = static_cast<float>(ratio); |
|
| 582 |
- ratiof -= static_cast<int32_t>(ratiof); |
|
| 583 |
- if (this->ply->interpolation == INTERPOLATION_COSINE) |
|
| 584 |
+ double ratio = this->reg.samplePosition; |
|
| 585 |
+ ratio -= static_cast<int32_t>(ratio); |
|
| 586 |
+ |
|
| 587 |
+ uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition); |
|
| 588 |
+ const auto &data = &this->reg.source->data[loc]; |
|
| 589 |
+ int32_t a = data[0], b; |
|
| 590 |
+ if (loc + 1 < this->reg.loopStart + this->reg.length) |
|
| 591 |
+ b = data[1]; |
|
| 592 |
+ else |
|
| 593 |
+ {
|
|
| 594 |
+ if (loc) |
|
| 595 |
+ {
|
|
| 596 |
+ int32_t am1 = data[-1]; |
|
| 597 |
+ b = 2 * a - am1; |
|
| 598 |
+ } |
|
| 599 |
+ else |
|
| 600 |
+ b = a; |
|
| 601 |
+ } |
|
| 602 |
+ |
|
| 603 |
+ if (this->ply->interpolation == INTERPOLATION_BSPLINE || this->ply->interpolation == INTERPOLATION_HERMITE || this->ply->interpolation == INTERPOLATION_OPTIMAL) |
|
| 604 |
+ {
|
|
| 605 |
+ int32_t c, z; |
|
| 606 |
+ if (loc + 2 < this->reg.loopStart + this->reg.length) |
|
| 607 |
+ c = data[2]; |
|
| 608 |
+ else |
|
| 609 |
+ {
|
|
| 610 |
+ if (loc) |
|
| 611 |
+ {
|
|
| 612 |
+ int32_t am1 = data[-1]; |
|
| 613 |
+ c = 3 * a - 2 * am1; |
|
| 614 |
+ } |
|
| 615 |
+ else |
|
| 616 |
+ c = a; |
|
| 617 |
+ } |
|
| 618 |
+ if (loc) |
|
| 619 |
+ z = data[-1]; |
|
| 620 |
+ else |
|
| 621 |
+ {
|
|
| 622 |
+ if (loc + 1 < this->reg.loopStart + this->reg.length) |
|
| 623 |
+ {
|
|
| 624 |
+ int32_t ap1 = data[1]; |
|
| 625 |
+ z = 2 * a - ap1; |
|
| 626 |
+ } |
|
| 627 |
+ else |
|
| 628 |
+ z = a; |
|
| 629 |
+ } |
|
| 630 |
+ |
|
| 631 |
+ double c0, c1, c2, c3; |
|
| 632 |
+ |
|
| 633 |
+ if (this->ply->interpolation == INTERPOLATION_BSPLINE) |
|
| 634 |
+ {
|
|
| 635 |
+ double zpb = z + b; |
|
| 636 |
+ c0 = 1 / 6.0 * zpb + 2 / 3.0 * a; |
|
| 637 |
+ c1 = 0.5 * (b - z); |
|
| 638 |
+ c2 = 0.5 * zpb - a; |
|
| 639 |
+ c3 = 0.5 * (a - b) + 1 / 6.0 * (c - z); |
|
| 640 |
+ return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 641 |
+ } |
|
| 642 |
+ if (this->ply->interpolation == INTERPOLATION_HERMITE) |
|
| 643 |
+ {
|
|
| 644 |
+ c0 = a; |
|
| 645 |
+ c1 = 0.5 * (b - z); |
|
| 646 |
+ c2 = z - 2.5 * a + 2 * b - 0.5 * c; |
|
| 647 |
+ c3 = 0.5 * (c - z) + 1.5 * (a - b); |
|
| 648 |
+ return static_cast<int32_t>(((c3 * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 649 |
+ } |
|
| 650 |
+ else |
|
| 651 |
+ {
|
|
| 652 |
+ ratio -= 0.5; |
|
| 653 |
+ double even1 = b + a, odd1 = b - a; |
|
| 654 |
+ double even2 = c + z, odd2 = c - z; |
|
| 655 |
+ c0 = even1 * 0.46835497211269561 + even2 * 0.03164502784253309; |
|
| 656 |
+ c1 = odd1 * 0.56001293337091440 + odd2 * 0.14666238593949288; |
|
| 657 |
+ c2 = even1 * -0.250038759826233691 + even2 * 0.25003876124297131; |
|
| 658 |
+ c3 = odd1 * -0.49949850957839148 + odd2 * 0.16649935475113800; |
|
| 659 |
+ double c4 = even1 * 0.00016095224137360 + even2 * -0.00016095810460478; |
|
| 660 |
+ return static_cast<int32_t>((((c4 * ratio + c3) * ratio + c2) * ratio + c1) * ratio + c0); |
|
| 661 |
+ } |
|
| 662 |
+ } |
|
| 663 |
+ else if (this->ply->interpolation == INTERPOLATION_COSINE) |
|
| 584 | 664 |
{
|
| 585 |
- double ratio2 = (1.0 - std::cos(ratiof * M_PI)) * 0.5; |
|
| 586 |
- return static_cast<int32_t>((1 - ratio2) * a + ratio2 * b); |
|
| 665 |
+ double ratio2 = (1.0 - std::cos(ratio * M_PI)) * 0.5; |
|
| 666 |
+ return static_cast<int32_t>(a + ratio2 * (b - a)); |
|
| 587 | 667 |
} |
| 588 | 668 |
else |
| 589 |
- return static_cast<int32_t>((1 - ratiof) * a + ratiof * b); |
|
| 669 |
+ return static_cast<int32_t>(a + ratio * (b - a)); |
|
| 590 | 670 |
} |
| 591 | 671 |
|
| 592 | 672 |
int32_t Channel::GenerateSample() |
| ... | ... |
@@ -599,16 +679,7 @@ int32_t Channel::GenerateSample() |
| 599 | 679 |
if (this->ply->interpolation == INTERPOLATION_NONE) |
| 600 | 680 |
return this->reg.source->data[static_cast<uint32_t>(this->reg.samplePosition)]; |
| 601 | 681 |
else |
| 602 |
- {
|
|
| 603 |
- uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition); |
|
| 604 |
- int32_t a = this->reg.source->data[loc], b; |
|
| 605 |
- if (loc < static_cast<uint32_t>(this->reg.loopStart + this->reg.length - 1)) |
|
| 606 |
- {
|
|
| 607 |
- b = this->reg.source->data[loc + 1]; |
|
| 608 |
- a = this->Interpolate(a, b, this->reg.samplePosition); |
|
| 609 |
- } |
|
| 610 |
- return a; |
|
| 611 |
- } |
|
| 682 |
+ return this->Interpolate(); |
|
| 612 | 683 |
} |
| 613 | 684 |
else |
| 614 | 685 |
{
|
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
/* |
| 2 | 2 |
* SSEQ Player - Channel structures |
| 3 | 3 |
* By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
| 4 |
- * Last modification on 2013-03-25 |
|
| 4 |
+ * Last modification on 2013-03-30 |
|
| 5 | 5 |
* |
| 6 | 6 |
* Adapted from source code of FeOS Sound System |
| 7 | 7 |
* By fincs |
| ... | ... |
@@ -18,7 +18,7 @@ |
| 18 | 18 |
#include "common.h" |
| 19 | 19 |
|
| 20 | 20 |
NDSSoundRegister::NDSSoundRegister() : volumeMul(0), volumeDiv(0), panning(0), waveDuty(0), repeatMode(0), format(0), enable(false), |
| 21 |
- source(NULL), timer(0), psgX(0), psgLast(0), psgLastCount(0), samplePosition(0), sampleIncrease(0), loopStart(0), length(0) |
|
| 21 |
+ source(nullptr), timer(0), psgX(0), psgLast(0), psgLastCount(0), samplePosition(0), sampleIncrease(0), loopStart(0), length(0) |
|
| 22 | 22 |
{
|
| 23 | 23 |
} |
| 24 | 24 |
|
| ... | ... |
@@ -39,13 +39,13 @@ void NDSSoundRegister::SetControlRegister(uint32_t reg) |
| 39 | 39 |
this->enable = (reg >> 31) & 0x01; |
| 40 | 40 |
} |
| 41 | 41 |
|
| 42 |
-TempSndReg::TempSndReg() : CR(0), SOURCE(NULL), TIMER(0), REPEAT_POINT(0), LENGTH(0) |
|
| 42 |
+TempSndReg::TempSndReg() : CR(0), SOURCE(nullptr), TIMER(0), REPEAT_POINT(0), LENGTH(0) |
|
| 43 | 43 |
{
|
| 44 | 44 |
} |
| 45 | 45 |
|
| 46 | 46 |
Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0), manualSweep(false), flags(), pan(0), extAmpl(0), velocity(0), extPan(0), |
| 47 | 47 |
key(0), ampl(0), extTune(0), orgKey(0), modType(0), modSpeed(0), modDepth(0), modRange(0), modDelay(0), modDelayCnt(0), modCounter(0), |
| 48 |
- sweepLen(0), sweepCnt(0), sweepPitch(0), attackLvl(0), sustainLvl(0x7F), decayRate(0), releaseRate(0xFFFF), noteLength(-1), vol(0), ply(NULL), reg() |
|
| 48 |
+ sweepLen(0), sweepCnt(0), sweepPitch(0), attackLvl(0), sustainLvl(0x7F), decayRate(0), releaseRate(0xFFFF), noteLength(-1), vol(0), ply(nullptr), reg() |
|
| 49 | 49 |
{
|
| 50 | 50 |
} |
| 51 | 51 |
|
| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,659 @@ |
| 1 |
+/* |
|
| 2 |
+ * SSEQ Player - Channel structures |
|
| 3 |
+ * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com] |
|
| 4 |
+ * Last modification on 2013-03-25 |
|
| 5 |
+ * |
|
| 6 |
+ * Adapted from source code of FeOS Sound System |
|
| 7 |
+ * By fincs |
|
| 8 |
+ * https://github.com/fincs/FSS |
|
| 9 |
+ * |
|
| 10 |
+ * Some code/concepts from DeSmuME |
|
| 11 |
+ * http://desmume.org/ |
|
| 12 |
+ */ |
|
| 13 |
+ |
|
| 14 |
+#define _USE_MATH_DEFINES |
|
| 15 |
+#include <cmath> |
|
| 16 |
+#include "Channel.h" |
|
| 17 |
+#include "Player.h" |
|
| 18 |
+#include "common.h" |
|
| 19 |
+ |
|
| 20 |
+NDSSoundRegister::NDSSoundRegister() : volumeMul(0), volumeDiv(0), panning(0), waveDuty(0), repeatMode(0), format(0), enable(false), |
|
| 21 |
+ source(NULL), timer(0), psgX(0), psgLast(0), psgLastCount(0), samplePosition(0), sampleIncrease(0), loopStart(0), length(0) |
|
| 22 |
+{
|
|
| 23 |
+} |
|
| 24 |
+ |
|
| 25 |
+void NDSSoundRegister::ClearControlRegister() |
|
| 26 |
+{
|
|
| 27 |
+ this->volumeMul = this->volumeDiv = this->panning = this->waveDuty = this->repeatMode = this->format = 0; |
|
| 28 |
+ this->enable = false; |
|
| 29 |
+} |
|
| 30 |
+ |
|
| 31 |
+void NDSSoundRegister::SetControlRegister(uint32_t reg) |
|
| 32 |
+{
|
|
| 33 |
+ this->volumeMul = reg & 0x7F; |
|
| 34 |
+ this->volumeDiv = (reg >> 8) & 0x03; |
|
| 35 |
+ this->panning = (reg >> 16) & 0x7F; |
|
| 36 |
+ this->waveDuty = (reg >> 24) & 0x07; |
|
| 37 |
+ this->repeatMode = (reg >> 27) & 0x03; |
|
| 38 |
+ this->format = (reg >> 29) & 0x03; |
|
| 39 |
+ this->enable = (reg >> 31) & 0x01; |
|
| 40 |
+} |
|
| 41 |
+ |
|
| 42 |
+TempSndReg::TempSndReg() : CR(0), SOURCE(NULL), TIMER(0), REPEAT_POINT(0), LENGTH(0) |
|
| 43 |
+{
|
|
| 44 |
+} |
|
| 45 |
+ |
|
| 46 |
+Channel::Channel() : chnId(-1), tempReg(), state(CS_NONE), trackId(-1), prio(0), manualSweep(false), flags(), pan(0), extAmpl(0), velocity(0), extPan(0), |
|
| 47 |
+ key(0), ampl(0), extTune(0), orgKey(0), modType(0), modSpeed(0), modDepth(0), modRange(0), modDelay(0), modDelayCnt(0), modCounter(0), |
|
| 48 |
+ sweepLen(0), sweepCnt(0), sweepPitch(0), attackLvl(0), sustainLvl(0x7F), decayRate(0), releaseRate(0xFFFF), noteLength(-1), vol(0), ply(NULL), reg() |
|
| 49 |
+{
|
|
| 50 |
+} |
|
| 51 |
+ |
|
| 52 |
+void Channel::UpdateVol(const Track &trk) |
|
| 53 |
+{
|
|
| 54 |
+ int finalVol = trk.ply->masterVol; |
|
| 55 |
+ finalVol += Cnv_Sust(trk.vol); |
|
| 56 |
+ finalVol += Cnv_Sust(trk.expr); |
|
| 57 |
+ if (finalVol < -AMPL_K) |
|
| 58 |
+ finalVol = -AMPL_K; |
|
| 59 |
+ this->extAmpl = finalVol; |
|
| 60 |
+} |
|
| 61 |
+ |
|
| 62 |
+void Channel::UpdatePan(const Track &trk) |
|
| 63 |
+{
|
|
| 64 |
+ this->extPan = trk.pan; |
|
| 65 |
+} |
|
| 66 |
+ |
|
| 67 |
+void Channel::UpdateTune(const Track &trk) |
|
| 68 |
+{
|
|
| 69 |
+ int tune = (static_cast<int>(this->key) - static_cast<int>(this->orgKey)) * 64; |
|
| 70 |
+ tune += (static_cast<int>(trk.pitchBend) * static_cast<int>(trk.pitchBendRange)) >> 1; |
|
| 71 |
+ this->extTune = tune; |
|
| 72 |
+} |
|
| 73 |
+ |
|
| 74 |
+void Channel::UpdateMod(const Track &trk) |
|
| 75 |
+{
|
|
| 76 |
+ this->modType = trk.modType; |
|
| 77 |
+ this->modSpeed = trk.modSpeed; |
|
| 78 |
+ this->modDepth = trk.modDepth; |
|
| 79 |
+ this->modRange = trk.modRange; |
|
| 80 |
+ this->modDelay = trk.modDelay; |
|
| 81 |
+} |
|
| 82 |
+ |
|
| 83 |
+void Channel::UpdatePorta(const Track &trk) |
|
| 84 |
+{
|
|
| 85 |
+ this->manualSweep = false; |
|
| 86 |
+ this->sweepPitch = trk.sweepPitch; |
|
| 87 |
+ this->sweepCnt = 0; |
|
| 88 |
+ if (!trk.state[TS_PORTABIT]) |
|
| 89 |
+ {
|
|
| 90 |
+ this->sweepLen = 0; |
|
| 91 |
+ return; |
|
| 92 |
+ } |
|
| 93 |
+ |
|
| 94 |
+ int diff = (static_cast<int>(trk.portaKey) - static_cast<int>(this->key)) << 22; |
|
| 95 |
+ this->sweepPitch += diff >> 16; |
|
| 96 |
+ |
|
| 97 |
+ if (!trk.portaTime) |
|
| 98 |
+ {
|
|
| 99 |
+ this->sweepLen = this->noteLength; |
|
| 100 |
+ this->manualSweep = true; |
|
| 101 |
+ } |
|
| 102 |
+ else |
|
| 103 |
+ {
|
|
| 104 |
+ int sq_time = static_cast<uint32_t>(trk.portaTime) * static_cast<uint32_t>(trk.portaTime); |
|
| 105 |
+ int abs_sp = std::abs(this->sweepPitch); |
|
| 106 |
+ this->sweepLen = (abs_sp * sq_time) >> 11; |
|
| 107 |
+ } |
|
| 108 |
+} |
|
| 109 |
+ |
|
| 110 |
+void Channel::Release() |
|
| 111 |
+{
|
|
| 112 |
+ this->noteLength = -1; |
|
| 113 |
+ this->prio = 1; |
|
| 114 |
+ this->state = CS_RELEASE; |
|
| 115 |
+} |
|
| 116 |
+ |
|
| 117 |
+void Channel::Kill() |
|
| 118 |
+{
|
|
| 119 |
+ this->state = CS_NONE; |
|
| 120 |
+ this->trackId = -1; |
|
| 121 |
+ this->prio = 0; |
|
| 122 |
+ this->reg.ClearControlRegister(); |
|
| 123 |
+ this->vol = 0; |
|
| 124 |
+ this->noteLength = -1; |
|
| 125 |
+} |
|
| 126 |
+ |
|
| 127 |
+static inline int getModFlag(int type) |
|
| 128 |
+{
|
|
| 129 |
+ switch (type) |
|
| 130 |
+ {
|
|
| 131 |
+ case 0: |
|
| 132 |
+ return CF_UPDTMR; |
|
| 133 |
+ case 1: |
|
| 134 |
+ return CF_UPDVOL; |
|
| 135 |
+ case 2: |
|
| 136 |
+ return CF_UPDPAN; |
|
| 137 |
+ default: |
|
| 138 |
+ return 0; |
|
| 139 |
+ } |
|
| 140 |
+} |
|
| 141 |
+ |
|
| 142 |
+void Channel::UpdateTrack() |
|
| 143 |
+{
|
|
| 144 |
+ if (!this->ply) |
|
| 145 |
+ return; |
|
| 146 |
+ |
|
| 147 |
+ int trkn = this->trackId; |
|
| 148 |
+ if (trkn == -1) |
|
| 149 |
+ return; |
|
| 150 |
+ |
|
| 151 |
+ auto &trackFlags = this->ply->tracks[trkn].updateFlags; |
|
| 152 |
+ if (trackFlags.none()) |
|
| 153 |
+ return; |
|
| 154 |
+ |
|
| 155 |
+ auto &trk = this->ply->tracks[trkn]; |
|
| 156 |
+ if (trackFlags[TUF_LEN]) |
|
| 157 |
+ {
|
|
| 158 |
+ int st = this->state; |
|
| 159 |
+ if (st > CS_START) |
|
| 160 |
+ {
|
|
| 161 |
+ if (st < CS_RELEASE && !--this->noteLength) |
|
| 162 |
+ this->Release(); |
|
| 163 |
+ if (this->manualSweep && this->sweepCnt < this->sweepLen) |
|
| 164 |
+ ++this->sweepCnt; |
|
| 165 |
+ } |
|
| 166 |
+ } |
|
| 167 |
+ if (trackFlags[TUF_VOL]) |
|
| 168 |
+ {
|
|
| 169 |
+ this->UpdateVol(trk); |
|
| 170 |
+ this->flags.set(CF_UPDVOL); |
|
| 171 |
+ } |
|
| 172 |
+ if (trackFlags[TUF_PAN]) |
|
| 173 |
+ {
|
|
| 174 |
+ this->UpdatePan(trk); |
|
| 175 |
+ this->flags.set(CF_UPDPAN); |
|
| 176 |
+ } |
|
| 177 |
+ if (trackFlags[TUF_TIMER]) |
|
| 178 |
+ {
|
|
| 179 |
+ this->UpdateTune(trk); |
|
| 180 |
+ this->flags.set(CF_UPDTMR); |
|
| 181 |
+ } |
|
| 182 |
+ if (trackFlags[TUF_MOD]) |
|
| 183 |
+ {
|
|
| 184 |
+ int oldType = this->modType; |
|
| 185 |
+ int newType = trk.modType; |
|
| 186 |
+ this->UpdateMod(trk); |
|
| 187 |
+ if (oldType != newType) |
|
| 188 |
+ {
|
|
| 189 |
+ this->flags.set(getModFlag(oldType)); |
|
| 190 |
+ this->flags.set(getModFlag(newType)); |
|
| 191 |
+ } |
|
| 192 |
+ } |
|
| 193 |
+} |
|
| 194 |
+ |
|
| 195 |
+static const uint16_t getpitchtbl[] = |
|
| 196 |
+{
|
|
| 197 |
+ 0x0000, 0x003B, 0x0076, 0x00B2, 0x00ED, 0x0128, 0x0164, 0x019F, |
|
| 198 |
+ 0x01DB, 0x0217, 0x0252, 0x028E, 0x02CA, 0x0305, 0x0341, 0x037D, |
|
| 199 |
+ 0x03B9, 0x03F5, 0x0431, 0x046E, 0x04AA, 0x04E6, 0x0522, 0x055F, |
|
| 200 |
+ 0x059B, 0x05D8, 0x0614, 0x0651, 0x068D, 0x06CA, 0x0707, 0x0743, |
|
| 201 |
+ 0x0780, 0x07BD, 0x07FA, 0x0837, 0x0874, 0x08B1, 0x08EF, 0x092C, |
|
| 202 |
+ 0x0969, 0x09A7, 0x09E4, 0x0A21, 0x0A5F, 0x0A9C, 0x0ADA, 0x0B18, |
|
| 203 |
+ 0x0B56, 0x0B93, 0x0BD1, 0x0C0F, 0x0C4D, 0x0C8B, 0x0CC9, 0x0D07, |
|
| 204 |
+ 0x0D45, 0x0D84, 0x0DC2, 0x0E00, 0x0E3F, 0x0E7D, 0x0EBC, 0x0EFA, |
|
| 205 |
+ 0x0F39, 0x0F78, 0x0FB6, 0x0FF5, 0x1034, 0x1073, 0x10B2, 0x10F1, |
|
| 206 |
+ 0x1130, 0x116F, 0x11AE, 0x11EE, 0x122D, 0x126C, 0x12AC, 0x12EB, |
|
| 207 |
+ 0x132B, 0x136B, 0x13AA, 0x13EA, 0x142A, 0x146A, 0x14A9, 0x14E9, |
|
| 208 |
+ 0x1529, 0x1569, 0x15AA, 0x15EA, 0x162A, 0x166A, 0x16AB, 0x16EB, |
|
| 209 |
+ 0x172C, 0x176C, 0x17AD, 0x17ED, 0x182E, 0x186F, 0x18B0, 0x18F0, |
|
| 210 |
+ 0x1931, 0x1972, 0x19B3, 0x19F5, 0x1A36, 0x1A77, 0x1AB8, 0x1AFA, |
|
| 211 |
+ 0x1B3B, 0x1B7D, 0x1BBE, 0x1C00, 0x1C41, 0x1C83, 0x1CC5, 0x1D07, |
|
| 212 |
+ 0x1D48, 0x1D8A, 0x1DCC, 0x1E0E, 0x1E51, 0x1E93, 0x1ED5, 0x1F17, |
|
| 213 |
+ 0x1F5A, 0x1F9C, 0x1FDF, 0x2021, 0x2064, 0x20A6, 0x20E9, 0x212C, |
|
| 214 |
+ 0x216F, 0x21B2, 0x21F5, 0x2238, 0x227B, 0x22BE, 0x2301, 0x2344, |
|
| 215 |
+ 0x2388, 0x23CB, 0x240E, 0x2452, 0x2496, 0x24D9, 0x251D, 0x2561, |
|
| 216 |
+ 0x25A4, 0x25E8, 0x262C, 0x2670, 0x26B4, 0x26F8, 0x273D, 0x2781, |
|
| 217 |
+ 0x27C5, 0x280A, 0x284E, 0x2892, 0x28D7, 0x291C, 0x2960, 0x29A5, |
|
| 218 |
+ 0x29EA, 0x2A2F, 0x2A74, 0x2AB9, 0x2AFE, 0x2B43, 0x2B88, 0x2BCD, |
|
| 219 |
+ 0x2C13, 0x2C58, 0x2C9D, 0x2CE3, 0x2D28, 0x2D6E, 0x2DB4, 0x2DF9, |
|
| 220 |
+ 0x2E3F, 0x2E85, 0x2ECB, 0x2F11, 0x2F57, 0x2F9D, 0x2FE3, 0x302A, |
|
| 221 |
+ 0x3070, 0x30B6, 0x30FD, 0x3143, 0x318A, 0x31D0, 0x3217, 0x325E, |
|
| 222 |
+ 0x32A5, 0x32EC, 0x3332, 0x3379, 0x33C1, 0x3408, 0x344F, 0x3496, |
|
| 223 |
+ 0x34DD, 0x3525, 0x356C, 0x35B4, 0x35FB, 0x3643, 0x368B, 0x36D3, |
|
| 224 |
+ 0x371A, 0x3762, 0x37AA, 0x37F2, 0x383A, 0x3883, 0x38CB, 0x3913, |
|
| 225 |
+ 0x395C, 0x39A4, 0x39ED, 0x3A35, 0x3A7E, 0x3AC6, 0x3B0F, 0x3B58, |
|
| 226 |
+ 0x3BA1, 0x3BEA, 0x3C33, 0x3C7C, 0x3CC5, 0x3D0E, 0x3D58, 0x3DA1, |
|
| 227 |
+ 0x3DEA, 0x3E34, 0x3E7D, 0x3EC7, 0x3F11, 0x3F5A, 0x3FA4, 0x3FEE, |
|
| 228 |
+ 0x4038, 0x4082, 0x40CC, 0x4116, 0x4161, 0x41AB, 0x41F5, 0x4240, |
|
| 229 |
+ 0x428A, 0x42D5, 0x431F, 0x436A, 0x43B5, 0x4400, 0x444B, 0x4495, |
|
| 230 |
+ 0x44E1, 0x452C, 0x4577, 0x45C2, 0x460D, 0x4659, 0x46A4, 0x46F0, |
|
| 231 |
+ 0x473B, 0x4787, 0x47D3, 0x481E, 0x486A, 0x48B6, 0x4902, 0x494E, |
|
| 232 |
+ 0x499A, 0x49E6, 0x4A33, 0x4A7F, 0x4ACB, 0x4B18, 0x4B64, 0x4BB1, |
|
| 233 |
+ 0x4BFE, 0x4C4A, 0x4C97, 0x4CE4, 0x4D31, 0x4D7E, 0x4DCB, 0x4E18, |
|
| 234 |
+ 0x4E66, 0x4EB3, 0x4F00, 0x4F4E, 0x4F9B, 0x4FE9, 0x5036, 0x5084, |
|
| 235 |
+ 0x50D2, 0x5120, 0x516E, 0x51BC, 0x520A, 0x5258, 0x52A6, 0x52F4, |
|
| 236 |
+ 0x5343, 0x5391, 0x53E0, 0x542E, 0x547D, 0x54CC, 0x551A, 0x5569, |
|
| 237 |
+ 0x55B8, 0x5607, 0x5656, 0x56A5, 0x56F4, 0x5744, 0x5793, 0x57E2, |
|
| 238 |
+ 0x5832, 0x5882, 0x58D1, 0x5921, 0x5971, 0x59C1, 0x5A10, 0x5A60, |
|
| 239 |
+ 0x5AB0, 0x5B01, 0x5B51, 0x5BA1, 0x5BF1, 0x5C42, 0x5C92, 0x5CE3, |
|
| 240 |
+ 0x5D34, 0x5D84, 0x5DD5, 0x5E26, 0x5E77, 0x5EC8, 0x5F19, 0x5F6A, |
|
| 241 |
+ 0x5FBB, 0x600D, 0x605E, 0x60B0, 0x6101, 0x6153, 0x61A4, 0x61F6, |
|
| 242 |
+ 0x6248, 0x629A, 0x62EC, 0x633E, 0x6390, 0x63E2, 0x6434, 0x6487, |
|
| 243 |
+ 0x64D9, 0x652C, 0x657E, 0x65D1, 0x6624, 0x6676, 0x66C9, 0x671C, |
|
| 244 |
+ 0x676F, 0x67C2, 0x6815, 0x6869, 0x68BC, 0x690F, 0x6963, 0x69B6, |
|
| 245 |
+ 0x6A0A, 0x6A5E, 0x6AB1, 0x6B05, 0x6B59, 0x6BAD, 0x6C01, 0x6C55, |
|
| 246 |
+ 0x6CAA, 0x6CFE, 0x6D52, 0x6DA7, 0x6DFB, 0x6E50, 0x6EA4, 0x6EF9, |
|
| 247 |
+ 0x6F4E, 0x6FA3, 0x6FF8, 0x704D, 0x70A2, 0x70F7, 0x714D, 0x71A2, |
|
| 248 |
+ 0x71F7, 0x724D, 0x72A2, 0x72F8, 0x734E, 0x73A4, 0x73FA, 0x7450, |
|
| 249 |
+ 0x74A6, 0x74FC, 0x7552, 0x75A8, 0x75FF, 0x7655, 0x76AC, 0x7702, |
|
| 250 |
+ 0x7759, 0x77B0, 0x7807, 0x785E, 0x78B4, 0x790C, 0x7963, 0x79BA, |
|
| 251 |
+ 0x7A11, 0x7A69, 0x7AC0, 0x7B18, 0x7B6F, 0x7BC7, 0x7C1F, 0x7C77, |
|
| 252 |
+ 0x7CCF, 0x7D27, 0x7D7F, 0x7DD7, 0x7E2F, 0x7E88, 0x7EE0, 0x7F38, |
|
| 253 |
+ 0x7F91, 0x7FEA, 0x8042, 0x809B, 0x80F4, 0x814D, 0x81A6, 0x81FF, |
|
| 254 |
+ 0x8259, 0x82B2, 0x830B, 0x8365, 0x83BE, 0x8418, 0x8472, 0x84CB, |
|
| 255 |
+ 0x8525, 0x857F, 0x85D9, 0x8633, 0x868E, 0x86E8, 0x8742, 0x879D, |
|
| 256 |
+ 0x87F7, 0x8852, 0x88AC, 0x8907, 0x8962, 0x89BD, 0x8A18, 0x8A73, |
|
| 257 |
+ 0x8ACE, 0x8B2A, 0x8B85, 0x8BE0, 0x8C3C, 0x8C97, 0x8CF3, 0x8D4F, |
|
| 258 |
+ 0x8DAB, 0x8E07, 0x8E63, 0x8EBF, 0x8F1B, 0x8F77, 0x8FD4, 0x9030, |
|
| 259 |
+ 0x908C, 0x90E9, 0x9146, 0x91A2, 0x91FF, 0x925C, 0x92B9, 0x9316, |
|
| 260 |
+ 0x9373, 0x93D1, 0x942E, 0x948C, 0x94E9, 0x9547, 0x95A4, 0x9602, |
|
| 261 |
+ 0x9660, 0x96BE, 0x971C, 0x977A, 0x97D8, 0x9836, 0x9895, 0x98F3, |
|
| 262 |
+ 0x9952, 0x99B0, 0x9A0F, 0x9A6E, 0x9ACD, 0x9B2C, 0x9B8B, 0x9BEA, |
|
| 263 |
+ 0x9C49, 0x9CA8, 0x9D08, 0x9D67, 0x9DC7, 0x9E26, 0x9E86, 0x9EE6, |
|
| 264 |
+ 0x9F46, 0x9FA6, 0xA006, 0xA066, 0xA0C6, 0xA127, 0xA187, 0xA1E8, |
|
| 265 |
+ 0xA248, 0xA2A9, 0xA30A, 0xA36B, 0xA3CC, 0xA42D, 0xA48E, 0xA4EF, |
|
| 266 |
+ 0xA550, 0xA5B2, 0xA613, 0xA675, 0xA6D6, 0xA738, 0xA79A, 0xA7FC, |
|
| 267 |
+ 0xA85E, 0xA8C0, 0xA922, 0xA984, 0xA9E7, 0xAA49, 0xAAAC, 0xAB0E, |
|
| 268 |
+ 0xAB71, 0xABD4, 0xAC37, 0xAC9A, 0xACFD, 0xAD60, 0xADC3, 0xAE27, |
|
| 269 |
+ 0xAE8A, 0xAEED, 0xAF51, 0xAFB5, 0xB019, 0xB07C, 0xB0E0, 0xB145, |
|
| 270 |
+ 0xB1A9, 0xB20D, 0xB271, 0xB2D6, 0xB33A, 0xB39F, 0xB403, 0xB468, |
|
| 271 |
+ 0xB4CD, 0xB532, 0xB597, 0xB5FC, 0xB662, 0xB6C7, 0xB72C, 0xB792, |
|
| 272 |
+ 0xB7F7, 0xB85D, 0xB8C3, 0xB929, 0xB98F, 0xB9F5, 0xBA5B, 0xBAC1, |
|
| 273 |
+ 0xBB28, 0xBB8E, 0xBBF5, 0xBC5B, 0xBCC2, 0xBD29, 0xBD90, 0xBDF7, |
|
| 274 |
+ 0xBE5E, 0xBEC5, 0xBF2C, 0xBF94, 0xBFFB, 0xC063, 0xC0CA, 0xC132, |
|
| 275 |
+ 0xC19A, 0xC202, 0xC26A, 0xC2D2, 0xC33A, 0xC3A2, 0xC40B, 0xC473, |
|
| 276 |
+ 0xC4DC, 0xC544, 0xC5AD, 0xC616, 0xC67F, 0xC6E8, 0xC751, 0xC7BB, |
|
| 277 |
+ 0xC824, 0xC88D, 0xC8F7, 0xC960, 0xC9CA, 0xCA34, 0xCA9E, 0xCB08, |
|
| 278 |
+ 0xCB72, 0xCBDC, 0xCC47, 0xCCB1, 0xCD1B, 0xCD86, 0xCDF1, 0xCE5B, |
|
| 279 |
+ 0xCEC6, 0xCF31, 0xCF9C, 0xD008, 0xD073, 0xD0DE, 0xD14A, 0xD1B5, |
|
| 280 |
+ 0xD221, 0xD28D, 0xD2F8, 0xD364, 0xD3D0, 0xD43D, 0xD4A9, 0xD515, |
|
| 281 |
+ 0xD582, 0xD5EE, 0xD65B, 0xD6C7, 0xD734, 0xD7A1, 0xD80E, 0xD87B, |
|
| 282 |
+ 0xD8E9, 0xD956, 0xD9C3, 0xDA31, 0xDA9E, 0xDB0C, 0xDB7A, 0xDBE8, |
|
| 283 |
+ 0xDC56, 0xDCC4, 0xDD32, 0xDDA0, 0xDE0F, 0xDE7D, 0xDEEC, 0xDF5B, |
|
| 284 |
+ 0xDFC9, 0xE038, 0xE0A7, 0xE116, 0xE186, 0xE1F5, 0xE264, 0xE2D4, |
|
| 285 |
+ 0xE343, 0xE3B3, 0xE423, 0xE493, 0xE503, 0xE573, 0xE5E3, 0xE654, |
|
| 286 |
+ 0xE6C4, 0xE735, 0xE7A5, 0xE816, 0xE887, 0xE8F8, 0xE969, 0xE9DA, |
|
| 287 |
+ 0xEA4B, 0xEABC, 0xEB2E, 0xEB9F, 0xEC11, 0xEC83, 0xECF5, 0xED66, |
|
| 288 |
+ 0xEDD9, 0xEE4B, 0xEEBD, 0xEF2F, 0xEFA2, 0xF014, 0xF087, 0xF0FA, |
|
| 289 |
+ 0xF16D, 0xF1E0, 0xF253, 0xF2C6, 0xF339, 0xF3AD, 0xF420, 0xF494, |
|
| 290 |
+ 0xF507, 0xF57B, 0xF5EF, 0xF663, 0xF6D7, 0xF74C, 0xF7C0, 0xF834, |
|
| 291 |
+ 0xF8A9, 0xF91E, 0xF992, 0xFA07, 0xFA7C, 0xFAF1, 0xFB66, 0xFBDC, |
|
| 292 |
+ 0xFC51, 0xFCC7, 0xFD3C, 0xFDB2, 0xFE28, 0xFE9E, 0xFF14, 0xFF8A |
|
| 293 |
+}; |
|
| 294 |
+ |
|
| 295 |
+static const uint8_t getvoltbl[] = |
|
| 296 |
+{
|
|
| 297 |
+ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
|
| 298 |
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
|
| 299 |
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
|
| 300 |
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
|
| 301 |
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
|
| 302 |
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, |
|
| 303 |
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, |
|
| 304 |
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, |
|
| 305 |
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, |
|
| 306 |
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, |
|
| 307 |
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, |
|
| 308 |
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, |
|
| 309 |
+ 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, |
|
| 310 |
+ 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, |
|
| 311 |
+ 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, |
|
| 312 |
+ 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, |
|
| 313 |
+ 0x09, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, |
|
| 314 |
+ 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0D, 0x0E, |
|
| 315 |
+ 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x10, 0x10, 0x10, 0x10, 0x10, |
|
| 316 |
+ 0x10, 0x11, 0x11, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, 0x14, |
|
| 317 |
+ 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x18, |
|
| 318 |
+ 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C, |
|
| 319 |
+ 0x1D, 0x1D, 0x1D, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, |
|
| 320 |
+ 0x22, 0x23, 0x23, 0x24, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x27, 0x28, 0x28, 0x29, |
|
| 321 |
+ 0x29, 0x2A, 0x2A, 0x2B, 0x2B, 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, 0x30, 0x31, 0x31, |
|
| 322 |
+ 0x32, 0x32, 0x33, 0x33, 0x34, 0x35, 0x35, 0x36, 0x36, 0x37, 0x38, 0x38, 0x39, 0x3A, 0x3A, 0x3B, |
|
| 323 |
+ 0x3C, 0x3C, 0x3D, 0x3E, 0x3F, 0x3F, 0x40, 0x41, 0x42, 0x42, 0x43, 0x44, 0x45, 0x45, 0x46, 0x47, |
|
| 324 |
+ 0x48, 0x49, 0x4A, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x52, 0x53, 0x54, 0x55, |
|
| 325 |
+ 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x67, |
|
| 326 |
+ 0x68, 0x69, 0x6A, 0x6B, 0x6D, 0x6E, 0x6F, 0x71, 0x72, 0x73, 0x75, 0x76, 0x77, 0x79, 0x7A, 0x7B, |
|
| 327 |
+ 0x7D, 0x7E, 0x7F, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, |
|
| 328 |
+ 0x26, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, 0x2C, 0x2C, 0x2D, |
|
| 329 |
+ 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, 0x30, 0x30, 0x31, 0x31, 0x32, 0x33, 0x33, 0x34, 0x34, 0x35, 0x36, |
|
| 330 |
+ 0x36, 0x37, 0x37, 0x38, 0x39, 0x39, 0x3A, 0x3B, 0x3B, 0x3C, 0x3D, 0x3E, 0x3E, 0x3F, 0x40, 0x40, |
|
| 331 |
+ 0x41, 0x42, 0x43, 0x43, 0x44, 0x45, 0x46, 0x47, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4D, |
|
| 332 |
+ 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, |
|
| 333 |
+ 0x5E, 0x5F, 0x60, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6F, 0x70, |
|
| 334 |
+ 0x71, 0x73, 0x74, 0x75, 0x77, 0x78, 0x79, 0x7B, 0x7C, 0x7E, 0x7E, 0x40, 0x41, 0x42, 0x43, 0x43, |
|
| 335 |
+ 0x44, 0x45, 0x46, 0x47, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, |
|
| 336 |
+ 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, |
|
| 337 |
+ 0x62, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6B, 0x6C, 0x6D, 0x6E, 0x70, 0x71, 0x72, 0x74, 0x75, |
|
| 338 |
+ 0x76, 0x78, 0x79, 0x7B, 0x7C, 0x7D, 0x7E, 0x40, 0x41, 0x42, 0x42, 0x43, 0x44, 0x45, 0x46, 0x46, |
|
| 339 |
+ 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, |
|
| 340 |
+ 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x65, 0x66, |
|
| 341 |
+ 0x67, 0x68, 0x69, 0x6A, 0x6C, 0x6D, 0x6E, 0x6F, 0x71, 0x72, 0x73, 0x75, 0x76, 0x77, 0x79, 0x7A, |
|
| 342 |
+ 0x7C, 0x7D, 0x7E, 0x7F |
|
| 343 |
+}; |
|
| 344 |
+ |
|
| 345 |
+// This function was obtained through disassembly of Ninty's sound driver |
|
| 346 |
+static inline uint16_t Timer_Adjust(uint16_t basetmr, int pitch) |
|
| 347 |
+{
|
|
| 348 |
+ int shift = 0; |
|
| 349 |
+ pitch = -pitch; |
|
| 350 |
+ |
|
| 351 |
+ while (pitch < 0) |
|
| 352 |
+ {
|
|
| 353 |
+ --shift; |
|
| 354 |
+ pitch += 0x300; |
|
| 355 |
+ } |
|
| 356 |
+ |
|
| 357 |
+ while (pitch >= 0x300) |
|
| 358 |
+ {
|
|
| 359 |
+ ++shift; |
|
| 360 |
+ pitch -= 0x300; |
|
| 361 |
+ } |
|
| 362 |
+ |
|
| 363 |
+ uint64_t tmr = static_cast<uint64_t>(basetmr) * (static_cast<uint32_t>(getpitchtbl[pitch]) + 0x10000); |
|
| 364 |
+ shift -= 16; |
|
| 365 |
+ if (shift <= 0) |
|
| 366 |
+ tmr >>= -shift; |
|
| 367 |
+ else if (shift < 32) |
|
| 368 |
+ {
|
|
| 369 |
+ if (tmr & ((~0ULL) << (32 - shift))) |
|
| 370 |
+ return 0xFFFF; |
|
| 371 |
+ tmr <<= shift; |
|
| 372 |
+ } |
|
| 373 |
+ else |
|
| 374 |
+ return 0x10; |
|
| 375 |
+ |
|
| 376 |
+ if (tmr < 0x10) |
|
| 377 |
+ return 0x10; |
|
| 378 |
+ if (tmr > 0xFFFF) |
|
| 379 |
+ return 0xFFFF; |
|
| 380 |
+ return static_cast<uint16_t>(tmr); |
|
| 381 |
+} |
|
| 382 |
+ |
|
| 383 |
+static inline int calcVolDivShift(int x) |
|
| 384 |
+{
|
|
| 385 |
+ // VOLDIV(0) /1 >>0 |
|
| 386 |
+ // VOLDIV(1) /2 >>1 |
|
| 387 |
+ // VOLDIV(2) /4 >>2 |
|
| 388 |
+ // VOLDIV(3) /16 >>4 |
|
| 389 |
+ if (x < 3) |
|
| 390 |
+ return x; |
|
| 391 |
+ return 4; |
|
| 392 |
+} |
|
| 393 |
+ |
|
| 394 |
+void Channel::Update() |
|
| 395 |
+{
|
|
| 396 |
+ // Kill active channels that aren't physically active |
|
| 397 |
+ if (this->state > CS_START && !this->reg.enable) |
|
| 398 |
+ {
|
|
| 399 |
+ this->Kill(); |
|
| 400 |
+ return; |
|
| 401 |
+ } |
|
| 402 |
+ |
|
| 403 |
+ bool bNotInSustain = this->state != CS_SUSTAIN; |
|
| 404 |
+ bool bInStart = this->state == CS_START; |
|
| 405 |
+ bool bPitchSweep = this->sweepPitch && this->sweepLen && this->sweepCnt <= this->sweepLen; |
|
| 406 |
+ bool bModulation = !!this->modDepth; |
|
| 407 |
+ bool bVolNeedUpdate = this->flags[CF_UPDVOL] || bNotInSustain; |
|
| 408 |
+ bool bPanNeedUpdate = this->flags[CF_UPDPAN] || bInStart; |
|
| 409 |
+ bool bTmrNeedUpdate = this->flags[CF_UPDTMR] || bInStart || bPitchSweep; |
|
| 410 |
+ int modParam = 0; |
|
| 411 |
+ |
|
| 412 |
+ switch (this->state) |
|
| 413 |
+ {
|
|
| 414 |
+ case CS_NONE: |
|
| 415 |
+ return; |
|
| 416 |
+ case CS_START: |
|
| 417 |
+ this->reg.ClearControlRegister(); |
|
| 418 |
+ this->reg.source = this->tempReg.SOURCE; |
|
| 419 |
+ this->reg.loopStart = this->tempReg.REPEAT_POINT; |
|
| 420 |
+ this->reg.length = this->tempReg.LENGTH; |
|
| 421 |
+ this->ampl = AMPL_THRESHOLD; |
|
| 422 |
+ this->state = CS_ATTACK; |
|
| 423 |
+ // Fall down |
|
| 424 |
+ case CS_ATTACK: |
|
| 425 |
+ this->ampl = (static_cast<int>(this->ampl) * static_cast<int>(this->attackLvl)) / 255; |
|
| 426 |
+ if (!this->ampl) |
|
| 427 |
+ this->state = CS_DECAY; |
|
| 428 |
+ break; |
|
| 429 |
+ case CS_DECAY: |
|
| 430 |
+ {
|
|
| 431 |
+ this->ampl -= static_cast<int>(this->decayRate); |
|
| 432 |
+ int sustLvl = Cnv_Sust(this->sustainLvl) << 7; |
|
| 433 |
+ if (this->ampl <= sustLvl) |
|
| 434 |
+ {
|
|
| 435 |
+ this->ampl = sustLvl; |
|
| 436 |
+ this->state = CS_SUSTAIN; |
|
| 437 |
+ } |
|
| 438 |
+ break; |
|
| 439 |
+ } |
|
| 440 |
+ case CS_RELEASE: |
|
| 441 |
+ this->ampl -= static_cast<int>(this->releaseRate); |
|
| 442 |
+ if (this->ampl > AMPL_THRESHOLD) |
|
| 443 |
+ break; |
|
| 444 |
+ this->Kill(); |
|
| 445 |
+ return; |
|
| 446 |
+ } |
|
| 447 |
+ |
|
| 448 |
+ if (bModulation && this->modDelayCnt < this->modDelay) |
|
| 449 |
+ {
|
|
| 450 |
+ ++this->modDelayCnt; |
|
| 451 |
+ bModulation = false; |
|
| 452 |
+ } |
|
| 453 |
+ |
|
| 454 |
+ if (bModulation) |
|
| 455 |
+ {
|
|
| 456 |
+ switch (this->modType) |
|
| 457 |
+ {
|
|
| 458 |
+ case 0: |
|
| 459 |
+ bTmrNeedUpdate = true; |
|
| 460 |
+ break; |
|
| 461 |
+ case 1: |
|
| 462 |
+ bVolNeedUpdate = true; |
|
| 463 |
+ break; |
|
| 464 |
+ case 2: |
|
| 465 |
+ bPanNeedUpdate = true; |
|
| 466 |
+ } |
|
| 467 |
+ |
|
| 468 |
+ // Get the current modulation parameter |
|
| 469 |
+ modParam = Cnv_Sine(this->modCounter >> 8) * this->modRange * this->modDepth; |
|
| 470 |
+ |
|
| 471 |
+ if (!this->modType) |
|
| 472 |
+ modParam = static_cast<int64_t>(modParam * 60) >> 14; |
|
| 473 |
+ else |
|
| 474 |
+ // This ugly formula whose exact meaning and workings I cannot figure out is used for volume/pan modulation. |
|
| 475 |
+ modParam = ((modParam & ~0xFC000000) >> 8) | ((((modParam < 0 ? -1 : 0) << 6) | (static_cast<uint32_t>(modParam) >> 26)) << 18); |
|
| 476 |
+ |
|
| 477 |
+ // Update the modulation variables |
|
| 478 |
+ |
|
| 479 |
+ uint16_t speed = static_cast<uint16_t>(this->modSpeed) << 6; |
|
| 480 |
+ uint16_t counter = (this->modCounter + speed) >> 8; |
|
| 481 |
+ |
|
| 482 |
+ while (counter >= 0x80) |
|
| 483 |
+ counter -= 0x80; |
|
| 484 |
+ |
|
| 485 |
+ this->modCounter += speed; |
|
| 486 |
+ this->modCounter &= 0xFF; |
|
| 487 |
+ this->modCounter |= counter << 8; |
|
| 488 |
+ } |
|
| 489 |
+ |
|
| 490 |
+ if (bTmrNeedUpdate) |
|
| 491 |
+ {
|
|
| 492 |
+ int totalAdj = this->extTune; |
|
| 493 |
+ if (bModulation && !this->modType) |
|
| 494 |
+ totalAdj += modParam; |
|
| 495 |
+ if (bPitchSweep) |
|
| 496 |
+ {
|
|
| 497 |
+ int len = this->sweepLen; |
|
| 498 |
+ int cnt = this->sweepCnt; |
|
| 499 |
+ totalAdj += (static_cast<int64_t>(this->sweepPitch) * (len - cnt)) / len; |
|
| 500 |
+ if (!this->manualSweep) |
|
| 501 |
+ ++this->sweepCnt; |
|
| 502 |
+ } |
|
| 503 |
+ uint16_t tmr = this->tempReg.TIMER; |
|
| 504 |
+ |
|
| 505 |
+ if (totalAdj) |
|
| 506 |
+ tmr = Timer_Adjust(tmr, totalAdj); |
|
| 507 |
+ this->reg.timer = -tmr; |
|
| 508 |
+ this->reg.sampleIncrease = (ARM7_CLOCK / static_cast<double>(this->ply->sampleRate * 2)) / (0x10000 - this->reg.timer); |
|
| 509 |
+ this->flags.reset(CF_UPDTMR); |
|
| 510 |
+ } |
|
| 511 |
+ |
|
| 512 |
+ if (bVolNeedUpdate || bPanNeedUpdate) |
|
| 513 |
+ {
|
|
| 514 |
+ uint32_t cr = this->tempReg.CR; |
|
| 515 |
+ if (bVolNeedUpdate) |
|
| 516 |
+ {
|
|
| 517 |
+ int totalVol = this->ampl >> 7; |
|
| 518 |
+ totalVol += this->extAmpl; |
|
| 519 |
+ totalVol += this->velocity; |
|
| 520 |
+ if (bModulation && this->modType == 1) |
|
| 521 |
+ totalVol += modParam; |
|
| 522 |
+ totalVol += AMPL_K; |
|
| 523 |
+ if (totalVol < 0) |
|
| 524 |
+ totalVol = 0; |
|
| 525 |
+ |
|
| 526 |
+ cr &= ~(SOUND_VOL(0x7F) | SOUND_VOLDIV(3)); |
|
| 527 |
+ cr |= SOUND_VOL(static_cast<int>(getvoltbl[totalVol])); |
|
| 528 |
+ |
|
| 529 |
+ if (totalVol < AMPL_K - 240) |
|
| 530 |
+ cr |= SOUND_VOLDIV(3); |
|
| 531 |
+ else if (totalVol < AMPL_K - 120) |
|
| 532 |
+ cr |= SOUND_VOLDIV(2); |
|
| 533 |
+ else if (totalVol < AMPL_K - 60) |
|
| 534 |
+ cr |= SOUND_VOLDIV(1); |
|
| 535 |
+ |
|
| 536 |
+ this->vol = ((cr & SOUND_VOL(0x7F)) << 4) >> calcVolDivShift((cr & SOUND_VOLDIV(3)) >> 8); |
|
| 537 |
+ |
|
| 538 |
+ this->flags.reset(CF_UPDVOL); |
|
| 539 |
+ } |
|
| 540 |
+ |
|
| 541 |
+ if (bPanNeedUpdate) |
|
| 542 |
+ {
|
|
| 543 |
+ int realPan = this->pan; |
|
| 544 |
+ realPan += this->extPan; |
|
| 545 |
+ if (bModulation && this->modType == 2) |
|
| 546 |
+ realPan += modParam; |
|
| 547 |
+ realPan += 64; |
|
| 548 |
+ if (realPan < 0) |
|
| 549 |
+ realPan = 0; |
|
| 550 |
+ else if (realPan > 127) |
|
| 551 |
+ realPan = 127; |
|
| 552 |
+ |
|
| 553 |
+ cr &= ~SOUND_PAN(0x7F); |
|
| 554 |
+ cr |= SOUND_PAN(realPan); |
|
| 555 |
+ this->flags.reset(CF_UPDPAN); |
|
| 556 |
+ } |
|
| 557 |
+ |
|
| 558 |
+ this->tempReg.CR = cr; |
|
| 559 |
+ this->reg.SetControlRegister(cr); |
|
| 560 |
+ } |
|
| 561 |
+} |
|
| 562 |
+ |
|
| 563 |
+static const int16_t wavedutytbl[8][8] = |
|
| 564 |
+{
|
|
| 565 |
+ { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF },
|
|
| 566 |
+ { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF },
|
|
| 567 |
+ { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF },
|
|
| 568 |
+ { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF },
|
|
| 569 |
+ { -0x7FFF, -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF },
|
|
| 570 |
+ { -0x7FFF, -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF },
|
|
| 571 |
+ { -0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF },
|
|
| 572 |
+ { -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF, -0x7FFF }
|
|
| 573 |
+}; |
|
| 574 |
+ |
|
| 575 |
+#ifndef M_PI |
|
| 576 |
+static const double M_PI = 3.14159265358979323846; |
|
| 577 |
+#endif |
|
| 578 |
+ |
|
| 579 |
+int32_t Channel::Interpolate(int32_t a, int32_t b, double ratio) |
|
| 580 |
+{
|
|
| 581 |
+ float ratiof = static_cast<float>(ratio); |
|
| 582 |
+ ratiof -= static_cast<int32_t>(ratiof); |
|
| 583 |
+ if (this->ply->interpolation == INTERPOLATION_COSINE) |
|
| 584 |
+ {
|
|
| 585 |
+ double ratio2 = (1.0 - std::cos(ratiof * M_PI)) * 0.5; |
|
| 586 |
+ return static_cast<int32_t>((1 - ratio2) * a + ratio2 * b); |
|
| 587 |
+ } |
|
| 588 |
+ else |
|
| 589 |
+ return static_cast<int32_t>((1 - ratiof) * a + ratiof * b); |
|
| 590 |
+} |
|
| 591 |
+ |
|
| 592 |
+int32_t Channel::GenerateSample() |
|
| 593 |
+{
|
|
| 594 |
+ if (this->reg.samplePosition < 0) |
|
| 595 |
+ return 0; |
|
| 596 |
+ |
|
| 597 |
+ if (this->reg.format != 3) |
|
| 598 |
+ {
|
|
| 599 |
+ if (this->ply->interpolation == INTERPOLATION_NONE) |
|
| 600 |
+ return this->reg.source->data[static_cast<uint32_t>(this->reg.samplePosition)]; |
|
| 601 |
+ else |
|
| 602 |
+ {
|
|
| 603 |
+ uint32_t loc = static_cast<uint32_t>(this->reg.samplePosition); |
|
| 604 |
+ int32_t a = this->reg.source->data[loc], b; |
|
| 605 |
+ if (loc < static_cast<uint32_t>(this->reg.loopStart + this->reg.length - 1)) |
|
| 606 |
+ {
|
|
| 607 |
+ b = this->reg.source->data[loc + 1]; |
|
| 608 |
+ a = this->Interpolate(a, b, this->reg.samplePosition); |
|
| 609 |
+ } |
|
| 610 |
+ return a; |
|
| 611 |
+ } |
|
| 612 |
+ } |
|
| 613 |
+ else |
|
| 614 |
+ {
|
|
| 615 |
+ if (this->chnId < 8) |
|
| 616 |
+ return 0; |
|
| 617 |
+ else if (this->chnId < 14) |
|
| 618 |
+ return wavedutytbl[this->reg.waveDuty][static_cast<uint32_t>(this->reg.samplePosition) & 0x7]; |
|
| 619 |
+ else |
|
| 620 |
+ {
|
|
| 621 |
+ if (this->reg.psgLastCount != static_cast<uint32_t>(this->reg.samplePosition)) |
|
| 622 |
+ {
|
|
| 623 |
+ uint32_t max = static_cast<uint32_t>(this->reg.samplePosition); |
|
| 624 |
+ for (uint32_t i = this->reg.psgLastCount; i < max; ++i) |
|
| 625 |
+ {
|
|
| 626 |
+ if (this->reg.psgX & 0x1) |
|
| 627 |
+ {
|
|
| 628 |
+ this->reg.psgX = (this->reg.psgX >> 1) ^ 0x6000; |
|
| 629 |
+ this->reg.psgLast = -0x7FFF; |
|
| 630 |
+ } |
|
| 631 |
+ else |
|
| 632 |
+ {
|
|
| 633 |
+ this->reg.psgX >>= 1; |
|
| 634 |
+ this->reg.psgLast = 0x7FFF; |
|
| 635 |
+ } |
|
| 636 |
+ } |
|
| 637 |
+ |
|
| 638 |
+ this->reg.psgLastCount = static_cast<uint32_t>(this->reg.samplePosition); |
|
| 639 |
+ } |
|
| 640 |
+ |
|
| 641 |
+ return this->reg.psgLast; |
|
| 642 |
+ } |
|
| 643 |
+ } |
|
| 644 |
+} |
|
| 645 |
+ |
|
| 646 |
+void Channel::IncrementSample() |
|
| 647 |
+{
|
|
| 648 |
+ this->reg.samplePosition += this->reg.sampleIncrease; |
|
| 649 |
+ if (this->reg.format != 3 && this->reg.samplePosition >= (this->reg.loopStart + this->reg.length)) |
|
| 650 |
+ {
|
|
| 651 |
+ if (this->reg.repeatMode == 1) |
|
| 652 |
+ {
|
|
| 653 |
+ while (this->reg.samplePosition >= (this->reg.loopStart + this->reg.length)) |
|
| 654 |
+ this->reg.samplePosition -= this->reg.length; |
|
| 655 |
+ } |
|
| 656 |
+ else |
|
| 657 |
+ this->Kill(); |
|
| 658 |
+ } |
|
| 659 |
+} |