Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Instrument Set Table Expansion #162

Open
wants to merge 14 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions MMR.Randomizer/Builder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ private void WriteAudioSeq(Random random, OutputSettings _settings)
RomData.PointerizedSequences = new List<SequenceInfo>();
SequenceUtils.ReadSequenceInfo();
SequenceUtils.ReadInstrumentSetList();
SequenceUtils.ResetFreeBankIndex();
if (_cosmeticSettings.Music == Music.Random)
{
SequenceUtils.PointerizeSequenceSlots();
Expand Down Expand Up @@ -341,6 +342,10 @@ private void WriteMiscellaneousChanges()
}

WriteCrashDebuggerShow();

// Dolphin/WiiVC audiothread shutdown workaround
ReadWriteUtils.WriteU16ToROM(0xB3C000 + 0x0CD320, 0x1000);

}

/// <summary>
Expand Down Expand Up @@ -3373,6 +3378,7 @@ public void MakeROM(OutputSettings outputSettings, IProgressReporter progressRep
WriteInstruments(new Random(BitConverter.ToInt32(hash, 0)));

progressReporter.ReportProgress(73, "Writing music...");
SequenceUtils.MoveAudioBankTableToFile();
WriteAudioSeq(new Random(BitConverter.ToInt32(hash, 0)), outputSettings);
WriteMuteMusic();
WriteEnemyCombatMusicMute();
Expand Down
15 changes: 15 additions & 0 deletions MMR.Randomizer/Models/Rom/SequenceInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,20 @@ public void ClearUnavailableBanks()
|| (u.InstrumentSet.Hash != 0
&& u.InstrumentSet.Hash == RomData.InstrumentSetList[u.InstrumentSet.BankSlot].Hash)));
}

public bool CheckAvailableBanks()
{
// get list of banks that: their slot has not been modified, or their bank is already used by another song and can be reused
var banks = this.SequenceBinaryList.FindAll(u => u.InstrumentSet == null
|| (RomData.InstrumentSetList[u.InstrumentSet.BankSlot].Modified == 0
|| (u.InstrumentSet.Hash != 0
&& u.InstrumentSet.Hash == RomData.InstrumentSetList[u.InstrumentSet.BankSlot].Hash)));
if (banks.Count == 0)
{
return false;
}
return true;
}

}
}
30 changes: 30 additions & 0 deletions MMR.Randomizer/Resources/mods.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions MMR.Randomizer/Resources/mods.resx
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,9 @@
<data name="instant_pictobox" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>mods\instant-pictobox;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="instrumentset_patch" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>mods\instrumentset-patch;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="key_boss_open" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>mods\key-boss-open;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
Expand All @@ -316,12 +319,18 @@
<data name="lenient_goron_spikes" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>mods\lenient-goron-spikes.bin;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="loadnewaudiotable" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>mods\loadnewaudiotable;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="logo_text" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>mods\logo-text;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="misc_changes" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>mods\misc-changes;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="moveaudiostatebytes" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>mods\moveaudiostatebytes;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="movement_1" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>mods\movement-1;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
Expand Down
Binary file added MMR.Randomizer/Resources/mods/instrumentset-patch
Binary file not shown.
Binary file added MMR.Randomizer/Resources/mods/loadnewaudiotable
Binary file not shown.
Binary file added MMR.Randomizer/Resources/mods/moveaudiostatebytes
Binary file not shown.
127 changes: 113 additions & 14 deletions MMR.Randomizer/Utils/SequenceUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ public class SequenceUtils
public static int MAX_COMBAT_BUDGET = 0x3800; // unk
public static int MAX_TYPE2_MUSIC_BUDGET = 0x6000; // vanilla: 0x4100

public static int New_AudioBankTable = 0; // for mmfilelist
public static int NewInstrumentSetAddress; // for bgm shuffle functions to work on
public static int CurrentFreeBank = 0x29;


public static void ResetBudget()
{
MAX_BGM_BUDGET = 0x3800;
Expand Down Expand Up @@ -777,6 +782,67 @@ private static void RelocateSeq(int f)
ReadWriteUtils.WriteToROM(0x00C2739C, new byte[] { 0x3C, 0x08, 0x80, 0x0A, 0x8D, 0x05, (byte)(offset >> 8), (byte)(offset & 0xFF) });
}

public static void MoveAudioBankTableToFile()
{
// grab original audiobanktable out of code, plus extra for modifying
var table = ReadWriteUtils.ReadBytes(0xB3C000 + 0x13B6C0, 0x820);
New_AudioBankTable = RomUtils.AddNewFile(table);

// instrumentset_patch: modifies audiobank metadata read and writes, instrument/drum/sfx pointer read and writes,
// nops a metadata copy function, and sets a fixed size for the audiobank pointer index
ResourceUtils.ApplyHack(Resources.mods.instrumentset_patch);

// moveaudiostatebytes: sets where read and writes for sequence and instrumentset states go
// in this hack, they're moved from 0x80205008 to end of old instrumentset table in code and given more space
// if these don't get moved, new banks at 0x30 and up will overflow into sequence states and can knock out sound
ResourceUtils.ApplyHack(Resources.mods.moveaudiostatebytes);

// loadnewaudiotable: where the copy metadata function loop was, sets a jump to code placed at the old instrumentset list
// which DMAs new audiobanktable from a file, relocates the addresses in the table, and sets the
// instrumentset table pointer to the new file
ResourceUtils.ApplyHack(Resources.mods.loadnewaudiotable);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this file, can you change ADDIU SP, SP, 0x00 to ADDIU SP, SP, -0x18 at the start, and + 0x18 at the end? And also SW/LW RA 0x0010 (SP) to SW/LW RA 0x0014 (SP)


// can't update addresses in an audiobank table that's moved and not loaded yet
ReadWriteUtils.WriteCodeNOP(0x80190E70);
ReadWriteUtils.WriteCodeNOP(0x80190E74);
ReadWriteUtils.WriteCodeNOP(0x80190E78);
ReadWriteUtils.WriteCodeNOP(0x80190E7C);
ReadWriteUtils.WriteCodeNOP(0x80190E80);

var symbols = Symbols.Load();
var tableAddr = 0x80720000 + (symbols.PayloadEnd - symbols.PayloadStart); //payload ram address + length
ReadWriteUtils.WriteU32ToROM(0xC776C0, tableAddr); //RAM address to move audiobanktable into

int f = RomUtils.GetFileIndexForWriting(New_AudioBankTable);
var fileData = RomData.MMFileList[f].Addr;
ReadWriteUtils.WriteToROM(0xC776C4, (uint)fileData ); //VROM address of new audiobanktable
ReadWriteUtils.WriteU32ToROM(0xC776C8, 0x00000820); //file length

NewInstrumentSetAddress = RomData.MMFileList[f].Addr + 0x10;

ReadWriteUtils.WriteU16ToROM(RomData.MMFileList[f].Addr, 0x0080); // Increase AudioBankTable amount

// insert dummy metadata (kamaro's dance bank duplicates)
int dummybankindexOffset = NewInstrumentSetAddress + 0x280;
int totaldummybanks = 0x58;
ulong dummybankmetadata0 = 0x00021880000000D0;
ulong dummybankmetadata1 = 0x020101FF01000000;

for (int dummybankIndex = 0; dummybankIndex <= totaldummybanks; ++dummybankIndex)
{
ReadWriteUtils.WriteU64ToROM(dummybankindexOffset, dummybankmetadata0);
ReadWriteUtils.WriteU64ToROM(dummybankindexOffset + 0x08, dummybankmetadata1);
dummybankindexOffset += 0x10;
}

}

public static void ResetFreeBankIndex()
{
CurrentFreeBank = 0x29;
}


public static bool TestIfAvailableBanks(SequenceInfo testSeq, SequenceInfo targetSlot, StringBuilder log, Random rng, List<SequenceInfo> unassignedSequences)
{
/// test if the testSeq can be used with available instrument set slots
Expand All @@ -790,20 +856,34 @@ public static bool TestIfAvailableBanks(SequenceInfo testSeq, SequenceInfo targe
testSeq.SequenceBinaryList = testSeq.SequenceBinaryList.OrderBy(x => rng.Next()).ToList();
}

testSeq.ClearUnavailableBanks(); // clear the sequence list of {bank/sequence} we cannot use
//testSeq.ClearUnavailableBanks(); // clear the sequence list of {bank/sequence} we cannot use
//if (testSeq.SequenceBinaryList.Count == 0) // all removed, song is dead.
//{
// log.AppendLine($"{ testSeq.Name,-50} cannot be used because it requires custom audiobank(s) already claimed ");
// unassignedSequences.Remove(testSeq);
// return false;
//}

if (testSeq.SequenceBinaryList.Count == 0) // all removed, song is dead.
var testBanks = testSeq.CheckAvailableBanks();
if (testBanks == true)
{
log.AppendLine($"{ testSeq.Name,-50} cannot be used because it requires custom audiobank(s) already claimed ");
unassignedSequences.Remove(testSeq);
return false;
testSeq.ClearUnavailableBanks(); // remove any already claimed bank sequences
}

// some slots are rarely heard in-game, dont waste a custom instrument set on them, check if this slot is one of them
if (IsBlockedByLowUse(testSeq, targetSlot, log))
else // all custom banks have been claimed
{
return false;
if (CurrentFreeBank > 0x0080)
{
return false; // can't overwrite any more entries
}

testSeq.SequenceBinaryList[0].InstrumentSet.BankSlot = CurrentFreeBank;
}

// some slots are rarely heard in-game, dont waste a custom instrument set on them, check if this slot is one of them
//if (IsBlockedByLowUse(testSeq, targetSlot, log))
//{
// return false;
//}
}
return true; // sequences with banks, or without needing banks, available
}
Expand Down Expand Up @@ -923,6 +1003,10 @@ public static void AssignSequenceSlot(SequenceInfo slotSequence, SequenceInfo re
// if the song has a custom instrument set, lock the sequence, update inst set value, debug output
if (replacementSequence.SequenceBinaryList != null && replacementSequence.SequenceBinaryList[0] != null && replacementSequence.SequenceBinaryList[0].InstrumentSet != null)
{
if (replacementSequence.SequenceBinaryList[0].InstrumentSet.BankSlot == CurrentFreeBank)
{
CurrentFreeBank++;
}
replacementSequence.Instrument = replacementSequence.SequenceBinaryList[0].InstrumentSet.BankSlot; // update to the one we want to use
if (RomData.InstrumentSetList[replacementSequence.Instrument].Modified > 0)
{
Expand Down Expand Up @@ -1255,10 +1339,11 @@ public static void ReadInstrumentSetList()
/// traverse the whole audiobank index and grab details about every bank
/// use those details to generate a list from the vanilla game that we can modify as needed
RomData.InstrumentSetList = new List<InstrumentSetInfo>();
for (int audiobankIndex = 0; audiobankIndex <= 0x28; ++audiobankIndex)
// audiobankindex can go up to 0x80 with current extended bank table file
for (int audiobankIndex = 0; audiobankIndex <= 0x80; ++audiobankIndex)
{
// each bank has one 16 byte sentence of data, first word is address, second is length, last 2 words metadata
int audiobankIndexAddr = Addresses.AudiobankTable + (audiobankIndex * 0x10);
int audiobankIndexAddr = NewInstrumentSetAddress + (audiobankIndex * 0x10);
int audiobankBankOffset = (ReadWriteUtils.ReadU16(audiobankIndexAddr) << 16) + ReadWriteUtils.ReadU16(audiobankIndexAddr + 2);
int bankLength = (ReadWriteUtils.ReadU16(audiobankIndexAddr + 4) << 16) + ReadWriteUtils.ReadU16(audiobankIndexAddr + 6);

Expand Down Expand Up @@ -1383,15 +1468,16 @@ public static void WriteNewSoundSamples(List<InstrumentSetInfo> InstrumentSetLis
public static void RebuildAudioBank(List<InstrumentSetInfo> InstrumentSetList)
{
// get index for the old audiobank, we're putting it back in the same spot but letting it expand into audioseq's spot, which was moved to the end
int fid = RomUtils.GetFileIndexForWriting(Addresses.AudiobankTable);
int fid = RomUtils.GetFileIndexForWriting(NewInstrumentSetAddress);
// the DMA table doesn't point directly to the indextable on the rom, its part of a larger yaz0 file, we have to use an offset to get the address in the file
int audiobankIndexOffset = Addresses.AudiobankTable - RomData.MMFileList[RomUtils.GetFileIndexForWriting(Addresses.AudiobankTable)].Addr;
int audiobankIndexOffset = NewInstrumentSetAddress - RomData.MMFileList[RomUtils.GetFileIndexForWriting(NewInstrumentSetAddress)].Addr;

int audiobankBankOffset = 0;
var audiobankData = new byte[0];

// for each bank, concat onto the new bank byte object, update the table to match the new instrument sets
for (int audiobankIndex = 0; audiobankIndex <= 0x28; ++audiobankIndex)
// CurrentFreeBank is used so not all unused dummy audiobanks get written to rom
for (int audiobankIndex = 0; audiobankIndex <= CurrentFreeBank; ++audiobankIndex)
{
var currentBank = InstrumentSetList[audiobankIndex];
audiobankData = audiobankData.Concat(currentBank.BankBinary).ToArray();
Expand Down Expand Up @@ -1429,6 +1515,19 @@ public static void RebuildAudioBank(List<InstrumentSetInfo> InstrumentSetList)
var audiobankFile = RomData.MMFileList[RomUtils.GetFileIndexForWriting(Addresses.Audiobank)];
audiobankFile.Data = audiobankData;
audiobankFile.End = audiobankFile.Addr + audiobankFile.Data.Length;

// check if audiobank has overflowed past the old audioseq space and into audiotable
if (audiobankFile.End > RomData.MMFileList[5].Addr)
{
int wowthatsalotofbanks = audiobankFile.End - RomData.MMFileList[5].Addr;
string oopsy = wowthatsalotofbanks.ToString();
throw new Exception("\nAudio banks have overflowed into audiotable\n"
+ "by "
+ oopsy
+ " bytes.\n\n"
+ "Please try another seed for a different music roll, "
+ "or bring down the amount of MMRS files with custom banks.");
}
}
}
}