Browse code

Port: Use [[fallthrough]] attribute.

Clarissa Walker authored on 2024/08/22 20:58:59
Showing 1 changed files
... ...
@@ -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;
Browse code

Various changes:

* 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().

Naram Qashat authored on 2021/03/21 03:16:45
Showing 1 changed files
... ...
@@ -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
 			{
Browse code

Remove last modification date from files.

(I never remember to update these and besides, GitHub history can show when they were last modified.)

Naram Qashat authored on 2021/03/19 10:58:12
Showing 1 changed files
... ...
@@ -1,7 +1,6 @@
1 1
 /*
2 2
  * SSEQ Player - Channel structures
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2014-10-27
5 4
  *
6 5
  * Adapted from source code of FeOS Sound System
7 6
  * By fincs
Browse code

fix mingw build, clean up new warnings

Adam Higerd authored on 2021/02/11 17:42:05
Showing 1 changed files
... ...
@@ -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;
Browse code

[NCSF] Minor possible fix in sample increment

* While I am unsure if this would've ever happened, this will prevent the locations from being out-of-bounds.

Naram Qashat authored on 2020/08/07 23:24:33
Showing 1 changed files
... ...
@@ -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
 
Browse code

[NCSF] Small typo (or rather non-removal) in the previous fix

Naram Qashat authored on 2020/07/06 23:59:19
Showing 1 changed files
... ...
@@ -520,7 +520,7 @@ void Channel::Update()
520 520
 		uint32_t counter = this->modCounter + (this->modSpeed << 6);
521 521
 		while (counter >= 0x8000)
522 522
 			counter -= 0x8000;
523
-		this->modCounter += counter;
523
+		this->modCounter = counter;
524 524
 	}
525 525
 
526 526
 	if (bTmrNeedUpdate)
Browse code

[NCSF] Apply channel modulation fix from fincs

Naram Qashat authored on 2020/07/06 20:54:59
Showing 1 changed files
... ...
@@ -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)
Browse code

[NCSF] Applied sinc modification from kode54:

Sinc mode should not scale the window, just the sinc pulse.

Naram Qashat authored on 2014/10/27 04:15:11
Showing 1 changed files
... ...
@@ -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)
Browse code

[NCSF] Very minor cleanups.

Naram Qashat authored on 2014/10/24 19:58:46
Showing 1 changed files
... ...
@@ -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;
Browse code

[NCSF] Bump version number for the previous fixes.

Naram Qashat authored on 2014/10/23 23:27:37
Showing 1 changed files
... ...
@@ -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-18
4
+ * Last modification on 2014-10-23
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
Browse code

[NCSF] Documented what FSS functions were originally used.

* Changed default of modDelay to 0.
* Also minor cleanup.

Naram Qashat authored on 2014/10/23 23:19:16
Showing 1 changed files
... ...
@@ -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);
Browse code

[NCSF] Changed sinc interpolation to a Nuttall 3-term Window on suggestion from kode54.

Naram Qashat authored on 2014/10/23 23:03:52
Showing 1 changed files
... ...
@@ -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
 }
Browse code

[NCSF] Fixed unintentional infinite loop in the previous attack rate calculation fix.

Naram Qashat authored on 2014/10/23 21:52:35
Showing 1 changed files
... ...
@@ -543,8 +543,6 @@ void Channel::Update()
543 543
 		if (bVolNeedUpdate)
544 544
 		{
545 545
 			int totalVol = this->ampl >> 7;
546
-			if (totalVol == -1)
547
-				this->ampl = 0;
548 546
 			totalVol += this->extAmpl;
549 547
 			totalVol += this->velocity;
550 548
 			if (bModulation && this->modType == 1)
Browse code

[NCSF] Minor correction to the attack rate calculation.

(Basically, it should never allow the same volume level as the previous
calculation.)

Naram Qashat authored on 2014/10/22 17:55:03
Showing 1 changed files
... ...
@@ -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;
Browse code

[NCSF] Corrected attack rate calculation.

Naram Qashat authored on 2014/10/22 17:30:48
Showing 1 changed files
... ...
@@ -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)
Browse code

[NCSF] Correctly handle the SSEQ volume from the INFO block.

Naram Qashat authored on 2014/10/18 04:20:53
Showing 1 changed files
... ...
@@ -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)
Browse code

Reverted the sound changes back to the original FSS code, but with the fix to clamp the total volume.

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.

Naram Qashat authored on 2014/10/07 17:45:05
Showing 1 changed files
... ...
@@ -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);
Browse code

[NCSF] Removed the Cnv_Scale function as it seemed to cause sounds to be too loud in some cases.

Naram Qashat authored on 2014/10/05 20:17:36
Showing 1 changed files
... ...
@@ -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
 
Browse code

[NCSF] Fix volume issues with a little help from the Nintendo DS SDK.

Also added a clone of DeSmuME's Sound View that is only build during a
debug build, which helped to identify the above issues.

Naram Qashat authored on 2014/10/05 20:00:09
Showing 1 changed files
... ...
@@ -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);
Browse code

[NCSF] Minor comment fix from the previous NCSF commit.

Naram Qashat authored on 2014/09/28 00:13:39
Showing 1 changed files
... ...
@@ -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
 {
Browse code

[NCSF] Interpolation changes:

* 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.

Naram Qashat authored on 2014/09/28 00:07:18
Showing 1 changed files
... ...
@@ -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
 }
Browse code

Reverted Sinc interpolation back to the Lanczos window.

Naram Qashat authored on 2014/06/17 10:40:29
Showing 1 changed files
... ...
@@ -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
 }
Browse code

* Replaced Lanczos window with Hann window for the windowed sinc function in the NCSF plugin. * Added a ring buffer specifically designed for working with SWAVs to replace the one provided by kode54, still have to give him thanks for the original though. * Fixed clipping issue caused by invalid clamping values. * Minor fix to using the min()/max() functions of numeric_limits because Winamp's out.h includes windows.h without my specific wrapper to redefine things.

Naram Qashat authored on 2013/05/07 05:42:46
Showing 1 changed files
... ...
@@ -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
-}
Browse code

Minor update to scale the phase offset, thanks to kode54.

Naram Qashat authored on 2013/04/26 13:56:54
Showing 1 changed files
... ...
@@ -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)
Browse code

Fixed up the Lanczos interpolation in NCSF (thanks to kode54), also allowed the NCSF plugin to use 32-bit samples in it's GenerateSamples function.

Naram Qashat authored on 2013/04/26 00:54:28
Showing 1 changed files
... ...
@@ -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;
Browse code

Added Lanczos interpolation to the NCSF plugin, and cleaned up a bit of the other code, as well as removing pstdint.h since it's no longer needed.

Naram Qashat authored on 2013/04/23 20:29:21
Showing 1 changed files
... ...
@@ -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
 }
Browse code

Implemented circular interpolation buffer to fix interpolation, thanks to kode54 for the code.

Naram Qashat authored on 2013/04/18 20:43:31
Showing 1 changed files
... ...
@@ -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
+}
Browse code

Removed the optimal, lagrange, and hermite interpolations and added in 2nd-order osculating.

Naram Qashat authored on 2013/04/12 10:25:49
Showing 1 changed files
... ...
@@ -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
 	{
Browse code

* Added more interpolation methods to in_ncsf. * Cleaned up a little of the code in the Interpolate function in in_ncsf. * Made it so changes in the config can apply to a running song, depending on the player. * Slight optimization of in_ncsf's interpolation so it doesn't have as much std::vector accessing. * Stopped trying to use the slope of the points to determine points outside the sample's range, hopefully will stop some of the clipping.

Naram Qashat authored on 2013/04/10 14:39:59
Showing 1 changed files
... ...
@@ -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
 	}
Browse code

Utilize SSEQ's volume from it's INFO section, plus some minor optimizations.

Naram Qashat authored on 2013/04/07 16:39:00
Showing 1 changed files
... ...
@@ -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
Browse code

Added new interpolation methods, added version number in plugin description.

Naram Qashat authored on 2013/04/02 22:40:32
Showing 1 changed files
... ...
@@ -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
 	{
Browse code

Cleanup of some warnings, updating modification dates, using nullptr instead of NULL in some cases.

Naram Qashat authored on 2013/03/30 16:17:42
Showing 1 changed files
... ...
@@ -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
 
Browse code

Import actual code.

Naram Qashat authored on 2013/03/26 02:41:19
Showing 1 changed files
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
+}