1717#include < string>
1818#include < stack>
1919
20- DECLARE_FORMAT (JaiSeq);
20+ DECLARE_FORMAT (JaiSeqBMS);
21+ DECLARE_FORMAT (JaiSeqAAF);
22+ DECLARE_FORMAT (JaiSeqBAA);
2123
2224/* Names from JASystem::TSeqParser from framework.map in The Wind Waker. */
2325enum MML {
@@ -95,9 +97,10 @@ class JaiSeqTrack : public SeqTrack {
9597 void SetParam (uint32_t beginOffset, uint8_t param, uint16_t value) {
9698 if (param == MML_PROG)
9799 AddProgramChange (beginOffset, curOffset - beginOffset, value);
98- else if (param == MML_BANK)
100+ else if (param == MML_BANK) {
101+ AddBankSelectNoItem (value);
99102 AddUnknown (beginOffset, curOffset - beginOffset, L" Bank Select" );
100- else
103+ } else
101104 AddUnknown (beginOffset, curOffset - beginOffset);
102105 }
103106
@@ -399,7 +402,7 @@ class JaiSeqTrack : public SeqTrack {
399402class JaiSeqSeq : public VGMSeq {
400403public:
401404 JaiSeqSeq (RawFile *file, uint32_t offset, uint32_t length) :
402- VGMSeq (JaiSeqFormat ::name, file, offset, length) {
405+ VGMSeq (JaiSeqBMSFormat ::name, file, offset, length) {
403406 bAllowDiscontinuousTrackData = true ;
404407 }
405408
@@ -445,8 +448,6 @@ static bool MatchMagic(RawFile *file, uint32_t offs, const char *magic) {
445448
446449class JaiSeqSamp : public VGMSamp {
447450public:
448- uint8_t unityKey;
449-
450451 JaiSeqSamp (VGMSampColl *sampColl, uint32_t offset, RawFile *waFile_) :
451452 VGMSamp (sampColl, offset, 0x2C , 0 , 0 ), waFile(waFile_) {
452453 Load ();
@@ -538,6 +539,7 @@ class JaiSeqSamp : public VGMSamp {
538539 SetNumChannels (1 );
539540
540541 /* unknown */
542+
541543 unityKey = GetByte (dwOffset + 0x02 );
542544 SetRate (GetShortBE (dwOffset + 0x05 ) / 2 );
543545 /* unknown */
@@ -567,7 +569,7 @@ class JaiSeqSampCollWSYS : public VGMSampColl {
567569public:
568570 JaiSeqSampCollWSYS (RawFile *file, uint32_t offset, uint32_t length,
569571 std::wstring name = L" WSYS Sample Collection" )
570- : VGMSampColl(JaiSeqFormat ::name, file, offset, length, name) {}
572+ : VGMSampColl(JaiSeqAAFFormat ::name, file, offset, length, name) {}
571573private:
572574
573575 virtual bool GetSampleInfo () override {
@@ -677,7 +679,6 @@ class JaiSeqInstrBNK : public VGMInstr {
677679 uint32_t numSamples = GetWordBE (regionTableIdx);
678680 uint32_t sampleNum;
679681 VGMRgn *rgn;
680- JaiSeqSamp *samp;
681682
682683 regionTableIdx += 0x04 ;
683684 if (numSamples == 0x00 )
@@ -693,8 +694,6 @@ class JaiSeqInstrBNK : public VGMInstr {
693694 regionTableIdx += 0x04 ; /* frequency multiplier */
694695
695696 rgn = AddRgn (regionTableIdx, 0x18 , sampleNum, keyLow, keyHigh);
696- samp = (JaiSeqSamp *)parInstrSet->sampColl ->samples [sampleNum];
697- rgn->SetUnityKey (samp->unityKey );
698697
699698 /* Fake ADSR for now. */
700699 rgn->attack_time = ((double )attack) / 0x3FFF ;
@@ -743,7 +742,7 @@ class JaiSeqInstrSetBNK : public VGMInstrSet {
743742 uint32_t offset,
744743 uint32_t length,
745744 VGMSampColl *sampColl,
746- std::wstring name = L" JaiSeq Instrument Bank" ) : VGMInstrSet(JaiSeqFormat ::name, file, offset, length, name, sampColl) {}
745+ std::wstring name = L" JaiSeq Instrument Bank" ) : VGMInstrSet(JaiSeqBAAFormat ::name, file, offset, length, name, sampColl) {}
747746
748747private:
749748
@@ -861,7 +860,182 @@ static bool LoadBAA(RawFile *file) {
861860 return true ;
862861}
863862
864- void JaiSeqScanner::Scan (RawFile *file, void *info) {
863+ static double FrequencyRatioToCents (double freqRatio) {
864+ return round (1000000 * 1200 * log2 (freqRatio)) / 1000000.0 ;
865+ }
866+
867+ class JaiSeqInstrAAF : public VGMInstr {
868+ public:
869+ JaiSeqInstrAAF (VGMInstrSet *instrSet, uint32_t offset, uint32_t length, uint32_t theInstrNum, uint32_t theBank = 0 )
870+ : VGMInstr(instrSet, offset, length, theBank, theInstrNum) {}
871+
872+ private:
873+ virtual bool LoadInstr () override {
874+ if (!MatchMagic (vgmfile->rawfile , dwOffset, " INST" ))
875+ return false ;
876+
877+ uint32_t keyRgnCount = GetWordBE (dwOffset + 0x28 );
878+ uint32_t keyRgnIdx = dwOffset + 0x2C ;
879+ uint8_t keyLow = 0 ;
880+ for (uint32_t i = 0 ; i < keyRgnCount; i++) {
881+ uint32_t keyRgnBase = parInstrSet->dwOffset + GetWordBE (keyRgnIdx);
882+ keyRgnIdx += 0x04 ;
883+
884+ uint8_t keyHigh = GetByte (keyRgnBase);
885+
886+ uint32_t velRgnCount = GetWordBE (keyRgnBase + 0x04 );
887+ uint32_t velRgnIdx = keyRgnBase + 0x08 ;
888+ uint8_t velLow = 0 ;
889+ for (uint32_t j = 0 ; j < velRgnCount; j++) {
890+ uint32_t velRgnBase = parInstrSet->dwOffset + GetWordBE (velRgnIdx);
891+ uint8_t velHigh = GetByte (velRgnBase);
892+
893+ /* 0x04 is some sort of bank identifier? Doesn't seem to match the WSYS ID... */
894+ uint32_t sampleNum = GetShortBE (velRgnBase + 0x06 );
895+ /* 0x08 = unknown float */
896+ uint32_t freqMultBits = GetWordBE (velRgnBase + 0x0C );
897+ float freqMult = *((float *) &freqMultBits);
898+
899+ VGMRgn *rgn = AddRgn (keyRgnBase, 0 , sampleNum, keyLow, keyHigh, velLow, velHigh);
900+ rgn->SetFineTune (FrequencyRatioToCents (freqMult));
901+ velLow = velHigh + 1 ;
902+ velRgnIdx += 0x04 ;
903+ }
904+
905+ keyLow = keyHigh + 1 ;
906+ }
907+ }
908+ };
909+
910+ class JaiSeqInstrSetAAF : public VGMInstrSet {
911+ public:
912+ uint32_t wsysId;
913+ uint32_t bnkId;
914+
915+ JaiSeqInstrSetAAF (RawFile *file,
916+ uint32_t offset,
917+ uint32_t length,
918+ uint32_t wsysId_,
919+ VGMSampColl *sampColl = nullptr ,
920+ std::wstring name = L" JaiSeq AAF Instrument Bank" ) :
921+ VGMInstrSet (JaiSeqAAFFormat::name, file, offset, length, name, sampColl), wsysId(wsysId_) {}
922+
923+ private:
924+ virtual bool GetInstrPointers () override {
925+ if (!MatchMagic (rawfile, dwOffset, " IBNK" ))
926+ return false ;
927+
928+ unLength = GetWordBE (dwOffset + 0x04 );
929+ bnkId = GetWordBE (dwOffset + 0x08 );
930+
931+ wchar_t buf[64 ] = {};
932+ swprintf (buf, sizeof (buf) / sizeof (*buf), L" Bank_%04x" , bnkId);
933+ name = buf;
934+
935+ uint32_t bankOffs = dwOffset + 0x20 ;
936+ if (!MatchMagic (rawfile, bankOffs, " BANK" ))
937+ return false ;
938+
939+ uint32_t listIdx = bankOffs + 0x04 ;
940+ uint32_t instrNum = 0 ;
941+ while (true ) {
942+ uint32_t instrOffs = GetWordBE (listIdx);
943+ if (instrOffs == 0x00 )
944+ break ;
945+ uint32_t instrBase = dwOffset + instrOffs;
946+ aInstrs.push_back (new JaiSeqInstrAAF (this , instrBase, 0 , instrNum++));
947+ listIdx += 0x04 ;
948+ }
949+
950+ return true ;
951+ }
952+
953+ };
954+
955+ /* Handle the AAF (Audio Archive File?) format from Wind Waker. */
956+ static bool LoadAAF (RawFile *file) {
957+ uint32_t offset = 0x00 ;
958+
959+ std::vector<VGMSampColl *> wsys;
960+ std::map<uint32_t , VGMInstrSet *> bnk;
961+
962+ while (true ) {
963+ uint32_t chunkType = file->GetWordBE (offset);
964+ offset += 0x04 ;
965+
966+ switch (chunkType) {
967+ case 0x00 :
968+ /* End of archive. */
969+ goto end;
970+ case 0x01 :
971+ case 0x05 :
972+ case 0x06 :
973+ case 0x07 :
974+ while (true ) {
975+ uint32_t start = file->GetWordBE (offset);
976+ offset += 0x04 ;
977+ if (start == 0x00 )
978+ break ;
979+ offset += 0x04 ; /* size */
980+ }
981+ break ;
982+ case 0x02 : {
983+ /* bnk */
984+ while (true ) {
985+ uint32_t start = file->GetWordBE (offset);
986+ offset += 0x04 ;
987+ if (start == 0x00 )
988+ break ;
989+ offset += 0x04 ; /* size */
990+ uint32_t wsysId = file->GetWordBE (offset);
991+ offset += 0x04 ;
992+ JaiSeqInstrSetAAF *instrSet = new JaiSeqInstrSetAAF (file, start, 0 , wsysId);
993+ instrSet->LoadVGMFile ();
994+ bnk[instrSet->bnkId ] = instrSet;
995+ }
996+ break ;
997+ }
998+ case 0x03 : {
999+ /* wsys */
1000+ while (true ) {
1001+ uint32_t start = file->GetWordBE (offset);
1002+ offset += 0x04 ;
1003+ if (start == 0x00 )
1004+ break ;
1005+ offset += 0x04 ; /* size */
1006+ offset += 0x04 ; /* flag */
1007+ JaiSeqSampCollWSYS *sampColl = new JaiSeqSampCollWSYS (file, start, 0 );
1008+ sampColl->LoadVGMFile ();
1009+ wsys.push_back (sampColl);
1010+ }
1011+ break ;
1012+ }
1013+ }
1014+ }
1015+
1016+ end:
1017+
1018+ for (auto const &pair : bnk) {
1019+ VGMInstrSet *instrSet = pair.second ;
1020+
1021+ VGMSampColl *sampColl = wsys[((JaiSeqInstrSetAAF *)instrSet)->wsysId ];
1022+ VGMColl *coll = new VGMColl (*instrSet->GetName ());
1023+ coll->AddInstrSet (instrSet);
1024+ coll->AddSampColl (sampColl);
1025+ coll->Load ();
1026+ }
1027+
1028+ return true ;
1029+ }
1030+
1031+ void JaiSeqBMSScanner::Scan (RawFile *file, void *info) {
8651032 JaiSeqSeq *seq = new JaiSeqSeq (file, 0 , 0 ); seq->Load ();
866- // LoadBAA(file);
8671033}
1034+
1035+ void JaiSeqAAFScanner::Scan (RawFile *file, void *info) {
1036+ LoadAAF (file);
1037+ }
1038+
1039+ void JaiSeqBAAScanner::Scan (RawFile *file, void *info) {
1040+ LoadBAA (file);
1041+ }
0 commit comments