[NCSF] Utilize the PLAYER blocks in the SDAT if they exist.
[NCSF] Utilize the PLAYER blocks in the SDAT if they exist.

Backwards compatibility is kept by treating the lack of PLAYER info as
if all channels are able to be allocated.

--- a/src/in_ncsf/SSEQPlayer/INFOEntry.cpp
+++ b/src/in_ncsf/SSEQPlayer/INFOEntry.cpp
@@ -1,7 +1,7 @@
 /*
  * SSEQ Player - SDAT INFO Entry structures
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-03-21
+ * Last modification on 2014-10-25
  *
  * Nintendo DS Nitro Composer (SDAT) Specification document found at
  * http://www.feshrine.net/hacking/doc/nds-sdat.html
@@ -9,7 +9,7 @@
 
 #include "INFOEntry.h"
 
-INFOEntrySEQ::INFOEntrySEQ() : fileID(0), bank(0), vol(0)
+INFOEntrySEQ::INFOEntrySEQ() : fileID(0), bank(0), vol(0), ply(0)
 {
 }
 
@@ -23,7 +23,7 @@
 		this->vol = 0x7F; // Prevents nothing for volume
 	file.ReadLE<uint8_t>(); // cpr
 	file.ReadLE<uint8_t>(); // ppr
-	file.ReadLE<uint8_t>(); // ply
+	this->ply = file.ReadLE<uint8_t>();
 }
 
 INFOEntryBANK::INFOEntryBANK() : fileID(0)
@@ -45,5 +45,17 @@
 void INFOEntryWAVEARC::Read(PseudoFile &file)
 {
 	this->fileID = file.ReadLE<uint16_t>();
+	file.ReadLE<uint16_t>(); // unknown
 }
 
+INFOEntryPLAYER::INFOEntryPLAYER() : channelMask(0)
+{
+}
+
+void INFOEntryPLAYER::Read(PseudoFile &file)
+{
+	file.ReadLE<uint16_t>(); // maxSeqs
+	this->channelMask = file.ReadLE<uint16_t>();
+	file.ReadLE<uint32_t>(); // heapSize
+}
+

--- a/src/in_ncsf/SSEQPlayer/INFOEntry.h
+++ b/src/in_ncsf/SSEQPlayer/INFOEntry.h
@@ -1,7 +1,7 @@
 /*
  * SSEQ Player - SDAT INFO Entry structures
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2014-09-08
+ * Last modification on 2014-10-25
  *
  * Nintendo DS Nitro Composer (SDAT) Specification document found at
  * http://www.feshrine.net/hacking/doc/nds-sdat.html
@@ -25,6 +25,7 @@
 	uint16_t fileID;
 	uint16_t bank;
 	uint8_t vol;
+	uint8_t ply;
 
 	INFOEntrySEQ();
 
@@ -50,3 +51,12 @@
 	void Read(PseudoFile &file);
 };
 
+struct INFOEntryPLAYER : INFOEntry
+{
+	uint16_t channelMask;
+
+	INFOEntryPLAYER();
+
+	void Read(PseudoFile &file);
+};
+

--- a/src/in_ncsf/SSEQPlayer/INFOSection.cpp
+++ b/src/in_ncsf/SSEQPlayer/INFOSection.cpp
@@ -1,7 +1,7 @@
 /*
  * SSEQ Player - SDAT INFO Section structures
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-03-25
+ * Last modification on 2014-10-25
  *
  * Nintendo DS Nitro Composer (SDAT) Specification document found at
  * http://www.feshrine.net/hacking/doc/nds-sdat.html
@@ -28,7 +28,7 @@
 		}
 }
 
-INFOSection::INFOSection() : SEQrecord(), BANKrecord(), WAVEARCrecord()
+INFOSection::INFOSection() : SEQrecord(), BANKrecord(), WAVEARCrecord(), PLAYERrecord()
 {
 }
 
@@ -57,5 +57,10 @@
 		file.pos = startOfINFO + recordOffsets[REC_WAVEARC];
 		this->WAVEARCrecord.Read(file, startOfINFO);
 	}
+	if (recordOffsets[REC_PLAYER])
+	{
+		file.pos = startOfINFO + recordOffsets[REC_PLAYER];
+		this->PLAYERrecord.Read(file, startOfINFO);
+	}
 }
 

--- a/src/in_ncsf/SSEQPlayer/INFOSection.h
+++ b/src/in_ncsf/SSEQPlayer/INFOSection.h
@@ -1,7 +1,7 @@
 /*
  * SSEQ Player - SDAT INFO Section structures
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2014-09-08
+ * Last modification on 2014-10-25
  *
  * Nintendo DS Nitro Composer (SDAT) Specification document found at
  * http://www.feshrine.net/hacking/doc/nds-sdat.html
@@ -27,6 +27,7 @@
 	INFORecord<INFOEntrySEQ> SEQrecord;
 	INFORecord<INFOEntryBANK> BANKrecord;
 	INFORecord<INFOEntryWAVEARC> WAVEARCrecord;
+	INFORecord<INFOEntryPLAYER> PLAYERrecord;
 
 	INFOSection();
 

--- 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 2014-10-23
+ * Last modification on 2014-10-25
  *
  * Adapted from source code of FeOS Sound System
  * By fincs
@@ -11,7 +11,8 @@
 #include "Player.h"
 #include "common.h"
 
-Player::Player() : prio(0), nTracks(0), tempo(0), tempoCount(0), tempoRate(0), masterVol(0), sseqVol(0), sseq(nullptr), sampleRate(0), interpolation(INTERPOLATION_NONE)
+Player::Player() : prio(0), nTracks(0), tempo(0), tempoCount(0), tempoRate(0), masterVol(0), sseqVol(0), sseq(nullptr), allowedChannels(0), sampleRate(0),
+	interpolation(INTERPOLATION_NONE)
 {
 	memset(this->trackIds, 0, sizeof(this->trackIds));
 	for (size_t i = 0; i < 16; ++i)
@@ -99,6 +100,8 @@
 	for (int i = 0; i < arraySize; ++i)
 	{
 		int thisChnNo = chnArray[i];
+		if (!this->allowedChannels[thisChnNo])
+			continue;
 		Channel &thisChn = this->channels[thisChnNo];
 		Channel &curChn = this->channels[curChnNo];
 		if (curChnNo != -1 && thisChn.prio >= curChn.prio)

--- 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-10-18
+ * Last modification on 2014-10-25
  *
  * Adapted from source code of FeOS Sound System
  * By fincs
@@ -10,6 +10,7 @@
 
 #pragma once
 
+#include <bitset>
 #include "SSEQ.h"
 #include "Track.h"
 #include "Channel.h"
@@ -26,6 +27,7 @@
 	uint8_t trackIds[FSS_TRACKCOUNT];
 	Track tracks[FSS_MAXTRACKS];
 	Channel channels[16];
+	std::bitset<16> allowedChannels;
 	int16_t variables[32];
 
 	uint32_t sampleRate;

--- a/src/in_ncsf/SSEQPlayer/SDAT.cpp
+++ b/src/in_ncsf/SSEQPlayer/SDAT.cpp
@@ -1,7 +1,7 @@
 /*
  * SSEQ Player - SDAT structure
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-03-21
+ * Last modification on 2014-10-25
  *
  * Nintendo DS Nitro Composer (SDAT) Specification document found at
  * http://www.feshrine.net/hacking/doc/nds-sdat.html
@@ -14,7 +14,7 @@
 #include "FATSection.h"
 #include "convert.h"
 
-SDAT::SDAT(PseudoFile &file, uint32_t sseqToLoad) : sseq(), sbnk()
+SDAT::SDAT(PseudoFile &file, uint32_t sseqToLoad) : sseq(), sbnk(), player()
 {
 	// Read sections
 	NDSStdHeader header;
@@ -89,6 +89,12 @@
 			}
 			else
 				this->swar[i].release();
+
+		// Get PLAYER for this SSEQ, if it exists
+		if (!infoSection.PLAYERrecord.entries.empty())
+			this->player = infoSection.PLAYERrecord.entries[this->sseq->info.ply];
+		if (!this->player.channelMask)
+			this->player.channelMask = 0xFFFF;
 	}
 }
 

--- a/src/in_ncsf/SSEQPlayer/SDAT.h
+++ b/src/in_ncsf/SSEQPlayer/SDAT.h
@@ -1,7 +1,7 @@
 /*
  * SSEQ Player - SDAT structure
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2014-09-08
+ * Last modification on 2014-10-25
  *
  * Nintendo DS Nitro Composer (SDAT) Specification document found at
  * http://www.feshrine.net/hacking/doc/nds-sdat.html
@@ -20,6 +20,7 @@
 	std::unique_ptr<SSEQ> sseq;
 	std::unique_ptr<SBNK> sbnk;
 	std::unique_ptr<SWAR> swar[4];
+	INFOEntryPLAYER player;
 
 	SDAT(PseudoFile &file, uint32_t sseqToLoad);
 private:

--- a/src/in_ncsf/SSEQPlayer/SYMBSection.cpp
+++ b/src/in_ncsf/SSEQPlayer/SYMBSection.cpp
@@ -1,7 +1,7 @@
 /*
  * SSEQ Player - SDAT SYMB (Symbol/Filename) Section structures
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2013-03-25
+ * Last modification on 2014-10-25
  *
  * Nintendo DS Nitro Composer (SDAT) Specification document found at
  * http://www.feshrine.net/hacking/doc/nds-sdat.html
@@ -27,7 +27,7 @@
 		}
 }
 
-SYMBSection::SYMBSection() : SEQrecord(), BANKrecord(), WAVEARCrecord()
+SYMBSection::SYMBSection() : SEQrecord(), BANKrecord(), WAVEARCrecord(), PLAYERrecord()
 {
 }
 
@@ -56,5 +56,10 @@
 		file.pos = startOfSYMB + recordOffsets[REC_WAVEARC];
 		this->WAVEARCrecord.Read(file, startOfSYMB);
 	}
+	if (recordOffsets[REC_PLAYER])
+	{
+		file.pos = startOfSYMB + recordOffsets[REC_PLAYER];
+		this->PLAYERrecord.Read(file, startOfSYMB);
+	}
 }
 

--- a/src/in_ncsf/SSEQPlayer/SYMBSection.h
+++ b/src/in_ncsf/SSEQPlayer/SYMBSection.h
@@ -1,7 +1,7 @@
 /*
  * SSEQ Player - SDAT SYMB (Symbol/Filename) Section structures
  * By Naram Qashat (CyberBotX) [cyberbotx@cyberbotx.com]
- * Last modification on 2014-09-08
+ * Last modification on 2014-10-25
  *
  * Nintendo DS Nitro Composer (SDAT) Specification document found at
  * http://www.feshrine.net/hacking/doc/nds-sdat.html
@@ -29,6 +29,7 @@
 	SYMBRecord SEQrecord;
 	SYMBRecord BANKrecord;
 	SYMBRecord WAVEARCrecord;
+	SYMBRecord PLAYERrecord;
 
 	SYMBSection();
 

--- 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-23
+ * Last modification on 2014-10-25
  *
  * 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.10.3";
+std::string XSFConfig::versionNumber = "1.11";
 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-18
+ * Last modification on 2014-10-25
  *
  * Partially based on the vio*sf framework
  *
@@ -173,6 +173,7 @@
 	file.data = &this->sdatData;
 	this->sdat.reset(new SDAT(file, this->sseq));
 	auto *sseqToPlay = this->sdat->sseq.get();
+	this->player.allowedChannels = std::bitset<16>(this->sdat->player.channelMask);
 	this->player.sseqVol = Cnv_Scale(sseqToPlay->info.vol);
 	this->player.sampleRate = this->sampleRate;
 	this->player.Setup(sseqToPlay);