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 3 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
+}
... ...
@@ -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-18
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
... ...
@@ -127,6 +127,14 @@ struct Channel
127 127
 	const Player *ply;
128 128
 	NDSSoundRegister reg;
129 129
 
130
+	/*
131
+	 * Interpolation history buffer, which contains the maximum number of
132
+	 * samples required for any given interpolation mode. Doubled to
133
+	 * simplify the case of wrapping. Thanks to kode54 for providing this.
134
+	 */
135
+	uint32_t sampleHistoryPtr;
136
+	int16_t sampleHistory[16];
137
+
130 138
 	Channel();
131 139
 
132 140
 	void UpdateVol(const Track &trk);
... ...
@@ -141,6 +149,7 @@ struct Channel
141 149
 	int32_t Interpolate();
142 150
 	int32_t GenerateSample();
143 151
 	void IncrementSample();
152
+	void clearHistory();
144 153
 };
145 154
 
146 155
 #endif
... ...
@@ -1,7 +1,7 @@
1 1
 /*
2 2
  * SSEQ Player - Player structure
3 3
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
4
- * Last modification on 2013-04-01
4
+ * Last modification on 2013-04-18
5 5
  *
6 6
  * Adapted from source code of FeOS Sound System
7 7
  * By fincs
... ...
@@ -120,6 +120,7 @@ int Player::ChannelAlloc(int type, int priority)
120 120
 	this->channels[curChnNo].ply = this;
121 121
 	this->channels[curChnNo].noteLength = -1;
122 122
 	this->channels[curChnNo].vol = 0;
123
+	this->channels[curChnNo].clearHistory();
123 124
 	return curChnNo;
124 125
 }
125 126