[NCSF] Implemented the random, variable, and conditional commands. Also fixed loop counter.
[NCSF] Implemented the random, variable, and conditional commands. Also fixed loop counter.

file:a/README.txt -> file:b/README.txt
--- a/README.txt
+++ b/README.txt
@@ -52,6 +52,9 @@
                     - Added a clone of DeSmuME's Sound View that only shows up
                       in debug builds, was used to help me identify the above
                       issue to fix it.
+ v1.10 - 2014-10-13 - Implemented the random, variable, and conditional
+                      commands.
+                    - Fixed loop counter.
 
 This is a Winamp plugin to play NCSF files. NCSF is a PSF-style music format that
 uses SDAT files from Nintendo DS ROMs as it's "program".

--- a/src/in_ncsf/SSEQPlayer/Player.cpp
+++ b/src/in_ncsf/SSEQPlayer/Player.cpp
@@ -1,7 +1,7 @@
 /*
  * SSEQ Player - Player structure
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-05-07
+ * Last modification on 2014-10-13
  *
  * Adapted from source code of FeOS Sound System
  * By fincs
@@ -16,6 +16,7 @@
 	memset(this->trackIds, 0, sizeof(this->trackIds));
 	for (size_t i = 0; i < 16; ++i)
 		this->channels[i].chnId = i;
+	memset(this->variables, -1, sizeof(this->variables));
 }
 
 bool Player::Setup(const SSEQ *sseqToPlay)
@@ -57,6 +58,7 @@
 	this->tempoCount = 0;
 	this->tempoRate = 0x100;
 	this->masterVol = 0; // this is actually the highest level
+	memset(this->variables, -1, sizeof(this->variables));
 }
 
 void Player::FreeTracks()

--- a/src/in_ncsf/SSEQPlayer/Player.h
+++ b/src/in_ncsf/SSEQPlayer/Player.h
@@ -1,7 +1,7 @@
 /*
  * SSEQ Player - Player structure
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2014-09-08
+ * Last modification on 2014-10-13
  *
  * Adapted from source code of FeOS Sound System
  * By fincs
@@ -26,6 +26,7 @@
 	uint8_t trackIds[FSS_TRACKCOUNT];
 	Track tracks[FSS_MAXTRACKS];
 	Channel channels[16];
+	int16_t variables[32];
 
 	uint32_t sampleRate;
 	Interpolation interpolation;

--- a/src/in_ncsf/SSEQPlayer/Track.cpp
+++ b/src/in_ncsf/SSEQPlayer/Track.cpp
@@ -1,13 +1,15 @@
 /*
  * SSEQ Player - Track structure
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2014-10-05
+ * Last modification on 2014-10-13
  *
  * Adapted from source code of FeOS Sound System
  * By fincs
  * https://github.com/fincs/FSS
  */
 
+#include <functional>
+#include <cstdlib>
 #include "Track.h"
 #include "Player.h"
 #include "common.h"
@@ -35,9 +37,11 @@
 	this->ply = nullptr;
 
 	this->startPos = this->pos = nullptr;
-	memset(this->stack, 0, sizeof(this->stack));
+	std::fill_n(&this->stack[0], FSS_TRACKSTACKSIZE, StackValue());
 	this->stackPos = 0;
 	memset(this->loopCount, 0, sizeof(this->loopCount));
+	this->overriding() = false;
+	this->lastComparisonResult = this->processCommand = true;
 
 	this->wait = 0;
 	this->patch = 0;
@@ -298,10 +302,94 @@
 	SSEQ_CMD_RANDOM = 0xA0,
 	SSEQ_CMD_PRINTVAR = 0xD6,
 	SSEQ_CMD_IF = 0xA2,
-	SSEQ_CMD_UNSUP1 = 0xA1,
-	SSEQ_CMD_UNSUP2_LO = 0xB0,
-	SSEQ_CMD_UNSUP2_HI = 0xBD
+	SSEQ_CMD_FROMVAR = 0xA1,
+	SSEQ_CMD_SETVAR = 0xB0,
+	SSEQ_CMD_ADDVAR = 0xB1,
+	SSEQ_CMD_SUBVAR = 0xB2,
+	SSEQ_CMD_MULVAR = 0xB3,
+	SSEQ_CMD_DIVVAR = 0xB4,
+	SSEQ_CMD_SHIFTVAR = 0xB5,
+	SSEQ_CMD_RANDVAR = 0xB6,
+	SSEQ_CMD_CMP_EQ = 0xB8,
+	SSEQ_CMD_CMP_GE = 0xB9,
+	SSEQ_CMD_CMP_GT = 0xBA,
+	SSEQ_CMD_CMP_LE = 0xBB,
+	SSEQ_CMD_CMP_LT = 0xBC,
+	SSEQ_CMD_CMP_NE = 0xBD,
+
+	SSEQ_CMD_MUTE = 0xD7 // Unsupported
 };
+
+static auto varFuncSet = [](int16_t, int16_t value) { return value; };
+static auto varFuncAdd = [](int16_t var, int16_t value) -> int16_t { return var + value; };
+static auto varFuncSub = [](int16_t var, int16_t value) -> int16_t { return var - value; };
+static auto varFuncMul = [](int16_t var, int16_t value) -> int16_t { return var * value; };
+static auto varFuncDiv = [](int16_t var, int16_t value) -> int16_t { return var / value; };
+static auto varFuncShift = [](int16_t var, int16_t value) -> int16_t
+{
+	if (value < 0)
+		return var >> -value;
+	else
+		return var << value;
+};
+static auto varFuncRand = [](int16_t, int16_t value) -> int16_t
+{
+	if (value < 0)
+		return -(std::rand() % (-value + 1));
+	else
+		return std::rand() % (value + 1);
+};
+
+static inline std::function<int16_t (int16_t, int16_t)> VarFunc(int cmd)
+{
+	switch (cmd)
+	{
+		case SSEQ_CMD_SETVAR:
+			return varFuncSet;
+		case SSEQ_CMD_ADDVAR:
+			return varFuncAdd;
+		case SSEQ_CMD_SUBVAR:
+			return varFuncSub;
+		case SSEQ_CMD_MULVAR:
+			return varFuncMul;
+		case SSEQ_CMD_DIVVAR:
+			return varFuncDiv;
+		case SSEQ_CMD_SHIFTVAR:
+			return varFuncShift;
+		case SSEQ_CMD_RANDVAR:
+			return varFuncRand;
+		default:
+			return nullptr;
+	}
+}
+
+static auto compareFuncEq = [](int16_t a, int16_t b) { return a == b; };
+static auto compareFuncGe = [](int16_t a, int16_t b) { return a >= b; };
+static auto compareFuncGt = [](int16_t a, int16_t b) { return a > b; };
+static auto compareFuncLe = [](int16_t a, int16_t b) { return a <= b; };
+static auto compareFuncLt = [](int16_t a, int16_t b) { return a < b; };
+static auto compareFuncNe = [](int16_t a, int16_t b) { return a != b; };
+
+static inline std::function<bool (int16_t, int16_t)> CompareFunc(int cmd)
+{
+	switch (cmd)
+	{
+		case SSEQ_CMD_CMP_EQ:
+			return compareFuncEq;
+		case SSEQ_CMD_CMP_GE:
+			return compareFuncGe;
+		case SSEQ_CMD_CMP_GT:
+			return compareFuncGt;
+		case SSEQ_CMD_CMP_LE:
+			return compareFuncLe;
+		case SSEQ_CMD_CMP_LT:
+			return compareFuncLt;
+		case SSEQ_CMD_CMP_NE:
+			return compareFuncNe;
+		default:
+			return nullptr;
+	}
+}
 
 void Track::Run()
 {
@@ -323,21 +411,40 @@
 
 	while (!this->wait)
 	{
-		int cmd = read8(pData);
+		int cmd;
+		if (this->overriding())
+			cmd = this->overriding.cmd;
+		else
+			cmd = read8(pData);
 		if (cmd < 0x80)
 		{
 			// Note on
 			int key = cmd + this->transpose;
-			int vel = read8(pData);
-			int len = readvl(pData);
-			if (this->state[TS_NOTEWAIT])
-				this->wait = len;
-			if (this->state[TS_TIEBIT])
-				this->NoteOnTie(key, vel);
+			int vel;
+			int len;
+			if (this->overriding())
+			{
+				vel = this->overriding.extraValue;
+				len = this->overriding.value;
+			}
 			else
-				this->NoteOn(key, vel, len);
+			{
+				vel = read8(pData);
+				len = readvl(pData);
+			}
+			if (this->processCommand)
+			{
+				if (this->state[TS_NOTEWAIT])
+					this->wait = len;
+				if (this->state[TS_TIEBIT])
+					this->NoteOnTie(key, vel);
+				else
+					this->NoteOn(key, vel, len);
+			}
 		}
 		else
+		{
+			int value;
 			switch (cmd)
 			{
 				//-----------------------------------------------------------------
@@ -345,86 +452,156 @@
 				//-----------------------------------------------------------------
 
 				case SSEQ_CMD_REST:
-					this->wait = readvl(pData);
+					if (this->overriding())
+						value = this->overriding.value;
+					else
+						value = readvl(pData);
+					if (this->processCommand)
+						this->wait = value;
 					break;
 
 				case SSEQ_CMD_PATCH:
-					this->patch = readvl(pData);
+					if (this->overriding())
+						value = this->overriding.value;
+					else
+						value = readvl(pData);
+					if (this->processCommand)
+						this->patch = value;
 					break;
 
 				case SSEQ_CMD_GOTO:
-					*pData = &this->ply->sseq->data[read24(pData)];
+					value = read24(pData);
+					if (this->processCommand)
+						*pData = &this->ply->sseq->data[value];
 					break;
 
 				case SSEQ_CMD_CALL:
-				{
-					const uint8_t *dest = &this->ply->sseq->data[read24(pData)];
-					this->stack[this->stackPos++] = *pData;
-					*pData = dest;
-					break;
-				}
+					value = read24(pData);
+					if (this->processCommand && this->stackPos < FSS_TRACKSTACKSIZE)
+					{
+						const uint8_t *dest = &this->ply->sseq->data[value];
+						this->stack[this->stackPos++] = StackValue(STACKTYPE_CALL, *pData);
+						*pData = dest;
+					}
+					break;
 
 				case SSEQ_CMD_RET:
-					*pData = this->stack[--this->stackPos];
+					if (this->processCommand && this->stackPos && this->stack[this->stackPos - 1].type == STACKTYPE_CALL)
+						*pData = this->stack[--this->stackPos].dest;
 					break;
 
 				case SSEQ_CMD_PAN:
-					this->pan = read8(pData) - 64;
-					this->updateFlags.set(TUF_PAN);
+					if (this->overriding())
+						value = this->overriding.value;
+					else
+						value = read8(pData);
+					if (this->processCommand)
+					{
+						this->pan = value - 64;
+						this->updateFlags.set(TUF_PAN);
+					}
 					break;
 
 				case SSEQ_CMD_VOL:
-					this->vol = read8(pData);
-					this->updateFlags.set(TUF_VOL);
+					if (this->overriding())
+						value = this->overriding.value;
+					else
+						value = read8(pData);
+					if (this->processCommand)
+					{
+						this->vol = value;
+						this->updateFlags.set(TUF_VOL);
+					}
 					break;
 
 				case SSEQ_CMD_MASTERVOL:
-					this->ply->masterVol = Cnv_Sust(read8(pData));
-					for (uint8_t i = 0; i < this->ply->nTracks; ++i)
-						this->ply->tracks[this->ply->trackIds[i]].updateFlags.set(TUF_VOL);
+					if (this->overriding())
+						value = this->overriding.value;
+					else
+						value = read8(pData);
+					if (this->processCommand)
+					{
+						this->ply->masterVol = Cnv_Sust(value);
+						for (uint8_t i = 0; i < this->ply->nTracks; ++i)
+							this->ply->tracks[this->ply->trackIds[i]].updateFlags.set(TUF_VOL);
+					}
 					break;
 
 				case SSEQ_CMD_PRIO:
-					this->prio = this->ply->prio + read8(pData);
+					value = read8(pData);
+					if (this->processCommand)
+						this->prio = this->ply->prio + value;
 					// Update here?
 					break;
 
 				case SSEQ_CMD_NOTEWAIT:
-					this->state.set(TS_NOTEWAIT, !!read8(pData));
+					value = read8(pData);
+					if (this->processCommand)
+						this->state.set(TS_NOTEWAIT, !!value);
 					break;
 
 				case SSEQ_CMD_TIE:
-					this->state.set(TS_TIEBIT, !!read8(pData));
-					this->ReleaseAllNotes();
+					value = read8(pData);
+					if (this->processCommand)
+					{
+						this->state.set(TS_TIEBIT, !!value);
+						this->ReleaseAllNotes();
+					}
 					break;
 
 				case SSEQ_CMD_EXPR:
-					this->expr = read8(pData);
-					this->updateFlags.set(TUF_VOL);
+					if (this->overriding())
+						value = this->overriding.value;
+					else
+						value = read8(pData);
+					if (this->processCommand)
+					{
+						this->expr = value;
+						this->updateFlags.set(TUF_VOL);
+					}
 					break;
 
 				case SSEQ_CMD_TEMPO:
-					this->ply->tempo = read16(pData);
+					value = read16(pData);
+					if (this->processCommand)
+						this->ply->tempo = value;
 					break;
 
 				case SSEQ_CMD_END:
-					this->state.set(TS_END);
-					return;
+					if (this->processCommand)
+					{
+						this->state.set(TS_END);
+						return;
+					}
+					break;
 
 				case SSEQ_CMD_LOOPSTART:
-					this->loopCount[this->stackPos] = read8(pData);
-					this->stack[this->stackPos++] = *pData;
+					if (this->overriding())
+						value = this->overriding.value;
+					else
+						value = read8(pData);
+					if (this->processCommand && this->stackPos < FSS_TRACKSTACKSIZE)
+					{
+						this->loopCount[this->stackPos] = value;
+						this->stack[this->stackPos++] = StackValue(STACKTYPE_LOOP, *pData);
+					}
 					break;
 
 				case SSEQ_CMD_LOOPEND:
-					if (this->stackPos)
-					{
-						const uint8_t *rPos = this->stack[this->stackPos - 1];
+					if (this->processCommand && this->stackPos && this->stack[this->stackPos - 1].type == STACKTYPE_LOOP)
+					{
+						const uint8_t *rPos = this->stack[this->stackPos - 1].dest;
 						uint8_t &nR = this->loopCount[this->stackPos - 1];
 						uint8_t prevR = nR;
-						if (prevR && !--nR)
-							--this->stackPos;
-						*pData = rPos;
+						if (!prevR)
+							*pData = rPos;
+						else
+						{
+							if (--nR)
+								*pData = rPos;
+							else
+								--this->stackPos;
+						}
 					}
 					break;
 
@@ -433,17 +610,33 @@
 				//-----------------------------------------------------------------
 
 				case SSEQ_CMD_TRANSPOSE:
-					this->transpose = read8(pData);
+					if (this->overriding())
+						value = this->overriding.value;
+					else
+						value = read8(pData);
+					if (this->processCommand)
+						this->transpose = value;
 					break;
 
 				case SSEQ_CMD_PITCHBEND:
-					this->pitchBend = read8(pData);
-					this->updateFlags.set(TUF_TIMER);
+					if (this->overriding())
+						value = this->overriding.value;
+					else
+						value = read8(pData);
+					if (this->processCommand)
+					{
+						this->pitchBend = value;
+						this->updateFlags.set(TUF_TIMER);
+					}
 					break;
 
 				case SSEQ_CMD_PITCHBENDRANGE:
-					this->pitchBendRange = read8(pData);
-					this->updateFlags.set(TUF_TIMER);
+					value = read8(pData);
+					if (this->processCommand)
+					{
+						this->pitchBendRange = value;
+						this->updateFlags.set(TUF_TIMER);
+					}
 					break;
 
 				//-----------------------------------------------------------------
@@ -451,19 +644,39 @@
 				//-----------------------------------------------------------------
 
 				case SSEQ_CMD_ATTACK:
-					this->a = read8(pData);
+					if (this->overriding())
+						value = this->overriding.value;
+					else
+						value = read8(pData);
+					if (this->processCommand)
+						this->a = value;
 					break;
 
 				case SSEQ_CMD_DECAY:
-					this->d = read8(pData);
+					if (this->overriding())
+						value = this->overriding.value;
+					else
+						value = read8(pData);
+					if (this->processCommand)
+						this->d = value;
 					break;
 
 				case SSEQ_CMD_SUSTAIN:
-					this->s = read8(pData);
+					if (this->overriding())
+						value = this->overriding.value;
+					else
+						value = read8(pData);
+					if (this->processCommand)
+						this->s = value;
 					break;
 
 				case SSEQ_CMD_RELEASE:
-					this->r = read8(pData);
+					if (this->overriding())
+						value = this->overriding.value;
+					else
+						value = read8(pData);
+					if (this->processCommand)
+						this->r = value;
 					break;
 
 				//-----------------------------------------------------------------
@@ -471,83 +684,202 @@
 				//-----------------------------------------------------------------
 
 				case SSEQ_CMD_PORTAKEY:
-					this->portaKey = read8(pData) + this->transpose;
-					this->state.set(TS_PORTABIT);
+					value = read8(pData);
+					if (this->processCommand)
+					{
+						this->portaKey = value + this->transpose;
+						this->state.set(TS_PORTABIT);
+						// Update here?
+					}
+					break;
+
+				case SSEQ_CMD_PORTAFLAG:
+					value = read8(pData);
+					if (this->processCommand)
+					{
+						this->state.set(TS_PORTABIT, !!value);
+						// Update here?
+					}
+					break;
+
+				case SSEQ_CMD_PORTATIME:
+					if (this->overriding())
+						value = this->overriding.value;
+					else
+						value = read8(pData);
+					if (this->processCommand)
+						this->portaTime = value;
 					// Update here?
 					break;
 
-				case SSEQ_CMD_PORTAFLAG:
-					this->state.set(TS_PORTABIT, !!read8(pData));
+				case SSEQ_CMD_SWEEPPITCH:
+					if (this->overriding())
+						value = this->overriding.value;
+					else
+						value = read16(pData);
+					if (this->processCommand)
+						this->sweepPitch = value;
 					// Update here?
 					break;
 
-				case SSEQ_CMD_PORTATIME:
-					this->portaTime = read8(pData);
-					// Update here?
-					break;
-
-				case SSEQ_CMD_SWEEPPITCH:
-					this->sweepPitch = read16(pData);
-					// Update here?
-					break;
-
 				//-----------------------------------------------------------------
 				// Modulation-related commands
 				//-----------------------------------------------------------------
 
 				case SSEQ_CMD_MODDEPTH:
-					this->modDepth = read8(pData);
-					this->updateFlags.set(TUF_MOD);
+					if (this->overriding())
+						value = this->overriding.value;
+					else
+						value = read8(pData);
+					if (this->processCommand)
+					{
+						this->modDepth = value;
+						this->updateFlags.set(TUF_MOD);
+					}
 					break;
 
 				case SSEQ_CMD_MODSPEED:
-					this->modSpeed = read8(pData);
-					this->updateFlags.set(TUF_MOD);
+					if (this->overriding())
+						value = this->overriding.value;
+					else
+						value = read8(pData);
+					if (this->processCommand)
+					{
+						this->modSpeed = value;
+						this->updateFlags.set(TUF_MOD);
+					}
 					break;
 
 				case SSEQ_CMD_MODTYPE:
-					this->modType = read8(pData);
-					this->updateFlags.set(TUF_MOD);
+					value = read8(pData);
+					if (this->processCommand)
+					{
+						this->modType = value;
+						this->updateFlags.set(TUF_MOD);
+					}
 					break;
 
 				case SSEQ_CMD_MODRANGE:
-					this->modRange = read8(pData);
-					this->updateFlags.set(TUF_MOD);
+					value = read8(pData);
+					if (this->processCommand)
+					{
+						this->modRange = value;
+						this->updateFlags.set(TUF_MOD);
+					}
 					break;
 
 				case SSEQ_CMD_MODDELAY:
-					this->modDelay = read16(pData);
-					this->updateFlags.set(TUF_MOD);
-					break;
+					if (this->overriding())
+						value = this->overriding.value;
+					else
+						value = read16(pData);
+					if (this->processCommand)
+					{
+						this->modDelay = value;
+						this->updateFlags.set(TUF_MOD);
+					}
+					break;
+
+				//-----------------------------------------------------------------
+				// Randomness-related commands
+				//-----------------------------------------------------------------
+
+				case SSEQ_CMD_RANDOM:
+				{
+					if (this->processCommand)
+						this->overriding() = true;
+					this->overriding.cmd = read8(pData);
+					if ((this->overriding.cmd >= SSEQ_CMD_SETVAR && this->overriding.cmd <= SSEQ_CMD_CMP_NE) || this->overriding.cmd < 0x80)
+						this->overriding.extraValue = read8(pData);
+					int16_t minVal = read16(pData);
+					int16_t maxVal = read16(pData);
+					this->overriding.value = (std::rand() % (maxVal - minVal + 1)) + minVal;
+					break;
+				}
 
 				//-----------------------------------------------------------------
 				// Variable-related commands
 				//-----------------------------------------------------------------
 
-				case SSEQ_CMD_RANDOM: // TODO
-					*pData += 5;
-					break;
-
-				case SSEQ_CMD_PRINTVAR: // TODO
-					*pData += 1;
-					break;
-
-				case SSEQ_CMD_UNSUP1: // TODO
+				case SSEQ_CMD_FROMVAR:
+					if (this->processCommand)
+						this->overriding() = true;
+					this->overriding.cmd = read8(pData);
+					if ((this->overriding.cmd >= SSEQ_CMD_SETVAR && this->overriding.cmd <= SSEQ_CMD_CMP_NE) || this->overriding.cmd < 0x80)
+						this->overriding.extraValue = read8(pData);
+					this->overriding.value = this->ply->variables[read8(pData)];
+					break;
+
+				case SSEQ_CMD_SETVAR:
+				case SSEQ_CMD_ADDVAR:
+				case SSEQ_CMD_SUBVAR:
+				case SSEQ_CMD_MULVAR:
+				case SSEQ_CMD_DIVVAR:
+				case SSEQ_CMD_SHIFTVAR:
+				case SSEQ_CMD_RANDVAR:
 				{
-					int t = read8(pData);
-					if (t >= SSEQ_CMD_UNSUP2_LO && t <= SSEQ_CMD_UNSUP2_HI)
-						*pData += 1;
-					*pData += 1;
+					int8_t varNo;
+					if (this->overriding())
+					{
+						varNo = this->overriding.extraValue;
+						value = this->overriding.value;
+					}
+					else
+					{
+						varNo = read8(pData);
+						value = read16(pData);
+					}
+					if (cmd == SSEQ_CMD_DIVVAR && !value) // Division by 0, skip it to prevent crashing
+						break;
+					if (this->processCommand)
+						this->ply->variables[varNo] = VarFunc(cmd)(this->ply->variables[varNo], value);
 					break;
 				}
 
-				case SSEQ_CMD_IF: // TODO
-					break;
-
-				default:
-					if (cmd >= SSEQ_CMD_UNSUP2_LO && cmd <= SSEQ_CMD_UNSUP2_HI) // TODO
-						*pData += 3;
+				//-----------------------------------------------------------------
+				// Conditional-related commands
+				//-----------------------------------------------------------------
+
+				case SSEQ_CMD_CMP_EQ:
+				case SSEQ_CMD_CMP_GE:
+				case SSEQ_CMD_CMP_GT:
+				case SSEQ_CMD_CMP_LE:
+				case SSEQ_CMD_CMP_LT:
+				case SSEQ_CMD_CMP_NE:
+				{
+					int8_t varNo;
+					if (this->overriding())
+					{
+						varNo = this->overriding.extraValue;
+						value = this->overriding.value;
+					}
+					else
+					{
+						varNo = read8(pData);
+						value = read16(pData);
+					}
+					if (this->processCommand)
+						this->lastComparisonResult = CompareFunc(cmd)(this->ply->variables[varNo], value);
+					break;
+				}
+
+				case SSEQ_CMD_IF:
+					this->processCommand = this->lastComparisonResult;
+					break;
+
+				case SSEQ_CMD_PRINTVAR:
+					++*pData;
+					break;
+
+				case SSEQ_CMD_MUTE: // UNSUPPORTED
+					++*pData;
 			}
-	}
-}
-
+		}
+
+		if (cmd != SSEQ_CMD_RANDOM && cmd != SSEQ_CMD_FROMVAR)
+			this->overriding() = false;
+		if (cmd != SSEQ_CMD_IF)
+			this->processCommand = true;
+	}
+}
+

--- a/src/in_ncsf/SSEQPlayer/Track.h
+++ b/src/in_ncsf/SSEQPlayer/Track.h
@@ -1,7 +1,7 @@
 /*
  * SSEQ Player - Track structure
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2014-09-08
+ * Last modification on 2014-10-13
  *
  * Adapted from source code of FeOS Sound System
  * By fincs
@@ -15,6 +15,33 @@
 
 struct Player;
 
+enum StackType
+{
+	STACKTYPE_CALL,
+	STACKTYPE_LOOP
+};
+
+struct StackValue
+{
+	StackType type;
+	const uint8_t *dest;
+
+	StackValue() : type(STACKTYPE_CALL), dest(nullptr) { }
+	StackValue(StackType newType, const uint8_t *newDest) : type(newType), dest(newDest) { }
+};
+
+struct Override
+{
+	bool overriding;
+	int cmd;
+	int value;
+	int extraValue;
+
+	Override() : overriding(false) { }
+	bool operator()() const { return this->overriding; }
+	bool &operator()() { return this->overriding; }
+};
+
 struct Track
 {
 	int8_t trackId;
@@ -25,9 +52,12 @@
 
 	const uint8_t *startPos;
 	const uint8_t *pos;
-	const uint8_t *stack[FSS_TRACKSTACKSIZE];
+	StackValue stack[FSS_TRACKSTACKSIZE];
 	uint8_t stackPos;
 	uint8_t loopCount[FSS_TRACKSTACKSIZE];
+	Override overriding;
+	bool lastComparisonResult;
+	bool processCommand;
 
 	int wait;
 	uint16_t patch;

--- a/src/in_ncsf/XSFConfig_NCSF.cpp
+++ b/src/in_ncsf/XSFConfig_NCSF.cpp
@@ -1,7 +1,7 @@
 /*
  * xSF - NCSF configuration
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2014-10-05
+ * Last modification on 2014-10-13
  *
  * Partially based on the vio*sf framework
  */
@@ -21,7 +21,7 @@
 
 unsigned XSFConfig::initSampleRate = 44100;
 std::string XSFConfig::commonName = "NCSF Decoder";
-std::string XSFConfig::versionNumber = "1.9.1";
+std::string XSFConfig::versionNumber = "1.10";
 unsigned XSFConfig_NCSF::initInterpolation = 4;
 std::string XSFConfig_NCSF::initMutes = "0000000000000000";
 

--- a/src/in_ncsf/XSFPlayer_NCSF.cpp
+++ b/src/in_ncsf/XSFPlayer_NCSF.cpp
@@ -1,7 +1,7 @@
 /*
  * xSF - NCSF Player
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2014-10-05
+ * Last modification on 2014-10-13
  *
  * Partially based on the vio*sf framework
  *
@@ -10,6 +10,8 @@
  */
 
 #include <memory>
+#include <cstdlib>
+#include <ctime>
 #include <zlib.h>
 #include "convert.h"
 #include "XSFPlayer_NCSF.h"
@@ -164,6 +166,8 @@
 	killSoundViewThread = false;
 	soundViewThreadHandle = CreateThread(nullptr, 0, soundViewThread, this, 0, nullptr);
 #endif
+
+	std::srand(static_cast<unsigned>(std::time(nullptr)));
 
 	PseudoFile file;
 	file.data = &this->sdatData;