text: #include <game.h>
  #include <sfx.h>
  #include "music.h"
  
  struct HijackedStream {
  	//const char *original;
  	//const char *originalFast;
  	u32 stringOffset;
  	u32 stringOffsetFast;
  	u32 infoOffset;
  	u8 originalID;
  	int streamID;
  };
  
  struct Hijacker {
  	HijackedStream stream[2];
  	u8 currentStream;
  	u8 currentCustomTheme;
  };
  
  
  
  const char* SongNameList [] = {
  	"AIRSHIP",
  	"BOSS_TOWER",
  	"MENU",
  	"UNDERWATER",
  	"ATHLETIC",
  	"CASTLE",
  	"MAIN",
  	"MOUNTAIN",
  	"TOWER",
  	"UNDERGROUND",
  	"DESERT",
  	"FIRE",
  	"FOREST",
  	"FREEZEFLAME",
  	"JAPAN",
  	"PUMPKIN",
  	"SEWER",
  	"SPACE",
  	"BOWSER",
  	"BONUS",	
  	"AMBUSH",	
  	"BRIDGE_DRUMS",	
  	"SNOW2",	
  	"MINIMEGA",	
  	"CLIFFS",
  	"AUTUMN",
  	"CRYSTALCAVES",
  	"GHOST_HOUSE",
  	"GRAVEYARD",
  	"JUNGLE",
  	"TROPICAL",
  	"SKY_CITY",
  	"SNOW",
  	"STAR_HAVEN",
  	"SINGALONG",
  	"FACTORY",
  	"TANK",
  	"TRAIN",
  	"YOSHIHOUSE",
  	"FACTORYB",
  	"CAVERN",
  	"SAND",
  	"SHYGUY",
  	"MINIGAME",
  	"BONUS_AREA",
  	"CHALLENGE",
  	"BOWSER_CASTLE",
  	"",
  	"",
  	"",
  	"",
  	"",
  	"",
  	"",
  	"",
  	"",
  	"BOSS_CASTLE",
  	"BOSS_AIRSHIP",
  	NULL	
  };
  
  
  
  // Offsets are from the start of the INFO block, not the start of the brsar.
  // INFO begins at 0x212C0, so that has to be subtracted from absolute offsets
  // within the brsar.
  
  #define _I(offs) ((offs)-0x212C0)
  
  Hijacker Hijackers[2] = {
  	{
  		{
  			{/*"athletic_lr.n.32.brstm", "athletic_fast_lr.n.32.brstm",*/ _I(0x4A8F8), _I(0x4A938), _I(0x476C4), 4, STRM_BGM_ATHLETIC},
  			{/*"BGM_SIRO.32.brstm", "BGM_SIRO_fast.32.brstm",*/ _I(0x4B2E8), _I(0x4B320), _I(0x48164), 10, STRM_BGM_SHIRO}
  		},
  		0, 0
  	},
  
  	{
  		{
  			{/*"STRM_BGM_CHIJOU.brstm", "STRM_BGM_CHIJOU_FAST.brstm",*/ _I(0x4A83C), _I(0x4A8B4), 0, 1, STRM_BGM_CHIJOU},
  			{/*"STRM_BGM_CHIKA.brstm", "STRM_BGM_CHIKA_FAST.brstm",*/ _I(0x4A878), _I(0x4A780), 0, 2, STRM_BGM_CHIKA},
  		},
  		0, 0
  	}
  };
  
  extern void *SoundRelatedClass;
  inline char *BrsarInfoOffset(u32 offset) {
  	return (char*)(*(u32*)(((u32)SoundRelatedClass) + 0x5CC)) + offset;
  }
  
  void FixFilesize(u32 streamNameOffset);
  
  u8 hijackMusicWithSongName(const char *songName, int themeID, bool hasFast, int channelCount, int trackCount, int *wantRealStreamID) {
  	Hijacker *hj = &Hijackers[channelCount==4?1:0];
  
  	// do we already have this theme in this slot?
  	// if so, don't switch streams
  	// if we do, NSMBW will think it's a different song, and restart it ...
  	// but if it's just an area transition where both areas are using the same
  	// song, we don't want that
  	if ((themeID >= 0) && hj->currentCustomTheme == themeID)
  		return hj->stream[hj->currentStream].originalID;
  
  	// which one do we use this time...?
  	int toUse = (hj->currentStream + 1) & 1;
  
  	hj->currentStream = toUse;
  	hj->currentCustomTheme = themeID;
  
  	// write the stream's info
  	HijackedStream *stream = &hj->stream[hj->currentStream];
  
  	if (stream->infoOffset) {
  		u16 *thing = (u16*)(BrsarInfoOffset(stream->infoOffset) + 4);
  		OSReport("Modifying stream info, at offset %x which is at pointer %x\n", stream->infoOffset, thing);
  		OSReport("It currently has: channel count %d, track bitfield 0x%x\n", thing[0], thing[1]);
  		thing[0] = channelCount;
  		thing[1] = (1 << trackCount) - 1;
  		OSReport("It has been set to: channel count %d, track bitfield 0x%x\n", thing[0], thing[1]);
  	}
  
  	sprintf(BrsarInfoOffset(stream->stringOffset), "stream/%s.brstm", songName);
  	sprintf(BrsarInfoOffset(stream->stringOffsetFast), hasFast?"stream/%s_F.brstm":"stream/%s.brstm", songName);
  
  	// update filesizes
  	FixFilesize(stream->stringOffset);
  	FixFilesize(stream->stringOffsetFast);
  
  	// done!
  	if (wantRealStreamID)
  		*wantRealStreamID = stream->streamID;
  
  	return stream->originalID;
  }
  
  
  //oh for fuck's sake
  #include "fileload.h"
  //#include <rvl/dvd.h>
  
  void FixFilesize(u32 streamNameOffset) {
  	char *streamName = BrsarInfoOffset(streamNameOffset);
  
  	char nameWithSound[80];
  	snprintf(nameWithSound, 79, "/Sound/%s", streamName);
  
  	s32 entryNum;
  	DVDHandle info;
  	
  	if ((entryNum = DVDConvertPathToEntrynum(nameWithSound)) >= 0) {
  		if (DVDFastOpen(entryNum, &info)) {
  			u32 *lengthPtr = (u32*)(streamName - 0x1C);
  			*lengthPtr = info.length;
  		}
  	} else
  		OSReport("What, I couldn't find \"%s\" :(\n", nameWithSound);
  }
  
  
  
  extern "C" u8 after_course_getMusicForZone(u8 realThemeID) {
  	if (realThemeID < 100)
  		return realThemeID;
  
  	bool usesDrums = (realThemeID >= 200);
  	const char *name = SongNameList[realThemeID - (usesDrums ? 200 : 100)];
  	return hijackMusicWithSongName(name, realThemeID, true, usesDrums?4:2, usesDrums?2:1, 0);
  }
  
  
  