diff --git a/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/Framework/Menus/MusicManagerMenu.cs b/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/Framework/Menus/MusicManagerMenu.cs new file mode 100644 index 00000000..1348761c --- /dev/null +++ b/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/Framework/Menus/MusicManagerMenu.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Xna.Framework.Graphics; + +namespace StardewSymphonyRemastered.Framework.Menus +{ + class MusicManagerMenu : StardewValley.Menus.IClickableMenu + { + public override void receiveRightClick(int x, int y, bool playSound = true) + { + throw new NotImplementedException(); + } + + public override void drawBackground(SpriteBatch b) + { + base.drawBackground(b); + } + } +} diff --git a/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/Framework/MusicManager.cs b/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/Framework/MusicManager.cs index 4a4ff992..88897ea4 100644 --- a/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/Framework/MusicManager.cs +++ b/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/Framework/MusicManager.cs @@ -174,10 +174,17 @@ namespace StardewSymphonyRemastered.Framework Dictionary> listOfValidDictionaries = new Dictionary>(); foreach(var v in this.musicPacks) { - var songList= v.Value.songInformation.getSongList(songListKey).Value; - if (songList.Count > 0) + try { - listOfValidDictionaries.Add(v.Value, songList); + var songList = v.Value.songInformation.getSongList(songListKey).Value; + if (songList.Count > 0) + { + listOfValidDictionaries.Add(v.Value, songList); + } + } + catch(Exception err) + { + } } return listOfValidDictionaries; @@ -189,14 +196,101 @@ namespace StardewSymphonyRemastered.Framework /// public void selectMusic(string songListKey) { + var listOfValidMusicPacks = getListOfApplicableMusicPacks(songListKey); + + string subKey = songListKey; + //Try to get more specific. + + //This chunk is to determine song specifics for location. + while (listOfValidMusicPacks.Count == 0) + { + if (subKey.Length == 0) break; + string[] subList= subKey.Split(SongSpecifics.seperator); + if (subList.Length == 0) break; //Because things would go bad otherwise. + subKey = ""; + for(int i = 0; i < subList.Length-1; i++) + { + subKey += subList[i]; + if (i != subList.Length - 2) + { + subKey += SongSpecifics.seperator; + } + } + if (subKey == "") break; + StardewSymphony.ModMonitor.Log(subKey,StardewModdingAPI.LogLevel.Alert); + listOfValidMusicPacks = getListOfApplicableMusicPacks(subKey); + if (listOfValidMusicPacks.Count == 0) + { + //No valid songs to play at this time. + StardewSymphony.ModMonitor.Log("Error: There are no songs to play across any music pack for the song key: " + subKey + ". Are you sure you did this properly?"); + //return; + } + } + + if (listOfValidMusicPacks.Count == 0) + { + //This chunk is used to determine more general seasonal specifics if song specifics couldn't be found. + subKey = songListKey; + string[] season = subKey.Split(SongSpecifics.seperator); + subKey = ""; + for (int i = 1; i < season.Length; i++) + { + subKey += season[i]; + if (i != season.Length - 1) + { + subKey += SongSpecifics.seperator; + } + } + if (string.IsNullOrEmpty(subKey)) + { + StardewSymphony.ModMonitor.Log("Error: There are no songs to play across any music pack for the song key: " + songListKey + ". Are you sure you did this properly?"); + return; + } + StardewSymphony.ModMonitor.Log(subKey, StardewModdingAPI.LogLevel.Alert); + listOfValidMusicPacks = getListOfApplicableMusicPacks(subKey); + if (listOfValidMusicPacks.Count == 0) + { + //No valid songs to play at this time. + StardewSymphony.ModMonitor.Log("Error: There are no songs to play across any music pack for the song key: " + subKey + ". Are you sure you did this properly?"); + //return; + } + //Try to get more specific. + + while (listOfValidMusicPacks.Count == 0) + { + if (subKey.Length == 0) break; + string[] subList = subKey.Split(SongSpecifics.seperator); + if (subList.Length == 0) break; //Because things would go bad otherwise. + subKey = ""; + for (int i = 0; i < subList.Length - 1; i++) + { + subKey += subList[i]; + if (i != subList.Length - 2) + { + subKey += SongSpecifics.seperator; + } + } + if (subKey == "") break; + StardewSymphony.ModMonitor.Log(subKey, StardewModdingAPI.LogLevel.Alert); + listOfValidMusicPacks = getListOfApplicableMusicPacks(subKey); + if (listOfValidMusicPacks.Count == 0) + { + //No valid songs to play at this time. + StardewSymphony.ModMonitor.Log("Error: There are no songs to play across any music pack for the song key: " + subKey + ". Are you sure you did this properly?"); + //return; + } + } + } + if (listOfValidMusicPacks.Count == 0) { //No valid songs to play at this time. - StardewSymphony.ModMonitor.Log("Error: There are no songs to play across any music pack. Are you sure you did this properly?"); + StardewSymphony.ModMonitor.Log("Error: There are no songs to play across any music pack for the song key: " + songListKey + ". Are you sure you did this properly?"); return; } - + + int randInt = packSelector.Next(0, listOfValidMusicPacks.Count-1); var musicPackPair = listOfValidMusicPacks.ElementAt(randInt); @@ -240,7 +334,25 @@ namespace StardewSymphonyRemastered.Framework } } } + /* + if(musicPack.GetType()==typeof(WavMusicPack)){ + foreach (var song in musicPack.songInformation.listOfSongsWithoutTriggers) + { + (musicPack as WavMusicPack).LoadWavFromFileToStream(song.pathToSong); + } + } + */ + this.musicPacks.Add(musicPack.musicPackInformation.name,musicPack); } + + + public void initializeSeasonalMusic() + { + foreach(var pack in this.musicPacks) + { + pack.Value.songInformation.initializeSeasonalMusic(); + } + } } } diff --git a/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/Framework/Song.cs b/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/Framework/Song.cs index f01f386b..ada048b5 100644 --- a/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/Framework/Song.cs +++ b/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/Framework/Song.cs @@ -9,6 +9,10 @@ namespace StardewSymphonyRemastered.Framework { /// /// The class to be used to manage individual songs. + /// + /// + /// + /// TODO: MAKE SMALL RELATIVE PATH TO SONG. /CONTENT/MUSIC/SONG /// public class Song { @@ -22,6 +26,11 @@ namespace StardewSymphonyRemastered.Framework /// public string name; + /// + /// The relative path to the song. + /// + public string relativePath; + /// /// Blank Constructor; /// @@ -38,6 +47,7 @@ namespace StardewSymphonyRemastered.Framework { this.pathToSong=PathToSong; this.name = getNameFromPath(this.pathToSong); + this.relativePath = this.getRelativePathFromFullPath(); } /// @@ -49,6 +59,7 @@ namespace StardewSymphonyRemastered.Framework { this.pathToSong = PathToSong; this.name = Name; + this.relativePath = this.getRelativePathFromFullPath(); } /// @@ -61,6 +72,31 @@ namespace StardewSymphonyRemastered.Framework return Path.GetFileNameWithoutExtension(path); } + public string getRelativePathFromFullPath() + { + string[] spliter = this.pathToSong.Split(Path.DirectorySeparatorChar); + string relative = ""; + int index = 0; + foreach(var str in spliter) //iterate across all of the strings until Content is found. + { + + if (str == "Content") + { + //Once content is found add it to the relative string and append a newline character. + for(int i = index; i < spliter.Length; i++) + { + relative += spliter[i]; + if (i != spliter.Length - 1) + { + relative += Path.DirectorySeparatorChar; + } + } + } + index++; + } + return relative; //Return the relative path string + } + /// /// Read the info from a .json file. /// diff --git a/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/Framework/SongSpecifics.cs b/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/Framework/SongSpecifics.cs index dbb7965d..253c8e17 100644 --- a/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/Framework/SongSpecifics.cs +++ b/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/Framework/SongSpecifics.cs @@ -30,6 +30,7 @@ namespace StardewSymphonyRemastered.Framework string[] weather; string[] daysOfWeek; string[] timesOfDay; + List menus; public static char seperator = '_'; /// @@ -70,15 +71,16 @@ namespace StardewSymphonyRemastered.Framework "day", "night" }; + menus = new List(); + menus.Add(typeof(StardewValley.Menus.TitleMenu).ToString()); + listOfSongsWithTriggers = new Dictionary>(); eventSongs = new Dictionary>(); festivalSongs = new Dictionary>(); this.listOfSongsWithoutTriggers = new List(); - - this.addSongLists(); - + this.addMenuMusic(); } @@ -96,6 +98,7 @@ namespace StardewSymphonyRemastered.Framework public static string getCurrentConditionalString() { string key = ""; + bool foundMenuString = false; if (Game1.eventUp == true) { //Get the event id an hijack it with some different music @@ -106,10 +109,25 @@ namespace StardewSymphonyRemastered.Framework //hijack the name of the festival and load some different songs // string s="Festival_FestivalName"; } + else if (Game1.activeClickableMenu!=null) + { + if (Game1.activeClickableMenu.GetType() == typeof(StardewValley.Menus.TitleMenu)) + { + key = Game1.activeClickableMenu.GetType().ToString(); + foundMenuString = true; + } + + } else { key = getLocationString() + seperator + getSeasonNameString() + seperator + getWeatherString() + seperator + getDayOfWeekString() + seperator + getTimeOfDayString(); } + + if(foundMenuString==false && key == "") + { + key = getLocationString() + seperator + getSeasonNameString() + seperator + getWeatherString() + seperator + getDayOfWeekString() + seperator + getTimeOfDayString(); + } + return key; } @@ -123,6 +141,7 @@ namespace StardewSymphonyRemastered.Framework foreach (var v in Game1.locations) { locations.Add(v.name); + StardewSymphony.ModMonitor.Log("Adding in song triggers for location: " + v.name); } } @@ -252,6 +271,12 @@ namespace StardewSymphonyRemastered.Framework { return Game1.currentLocation.name; } + + public static string getCurrentMenuString() + { + if (Game1.activeClickableMenu == null) return ""; + else return Game1.activeClickableMenu.GetType().ToString(); + } #endregion //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// @@ -268,6 +293,14 @@ namespace StardewSymphonyRemastered.Framework this.listOfSongsWithoutTriggers.Add(song); } + public void addMenuMusic() + { + foreach(var v in menus) + { + this.listOfSongsWithTriggers.Add(v, new List()); + } + } + /// /// Checks if the song exists at all in this music pack. /// @@ -282,7 +315,7 @@ namespace StardewSymphonyRemastered.Framework /// /// A pretty big function to add in all of the specific songs that play at certain locations_seasons_weather_dayOfWeek_times. /// - public void addSongLists() + public void initializeSeasonalMusic() { foreach (var loc in locations) { @@ -331,8 +364,15 @@ namespace StardewSymphonyRemastered.Framework /// public KeyValuePair>getSongList(string key) { - string keyPhrase = key.Split(seperator).ElementAt(0); - + string keyPhrase = ""; + try + { + keyPhrase= key.Split(seperator).ElementAt(0); + } + catch(Exception err) + { + keyPhrase = key; + } if (keyPhrase == "event") { @@ -358,6 +398,7 @@ namespace StardewSymphonyRemastered.Framework foreach(KeyValuePair> pair in listOfSongsWithTriggers) { + //StardewSymphony.ModMonitor.Log(pair.Key); if (pair.Key == key) return pair; } diff --git a/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/Framework/WavMusicPack.cs b/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/Framework/WavMusicPack.cs index eb311178..4c3d9bb3 100644 --- a/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/Framework/WavMusicPack.cs +++ b/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/Framework/WavMusicPack.cs @@ -1,4 +1,6 @@ -using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Audio; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -15,6 +17,23 @@ namespace StardewSymphonyRemastered.Framework public Song currentSong; public string songsDirectory; + /// + /// Used to actually play the song. + /// + DynamicSoundEffectInstance dynamicSound; + /// + /// Used to keep track of where in the song we are. + /// + int position; + /// + /// ??? + /// + int count; + /// + /// Used to store the info for the song. + /// + byte[] byteArray; + /// /// Constructor. /// @@ -55,12 +74,69 @@ namespace StardewSymphonyRemastered.Framework this.shortenedDirectory = directoryLocation; } + /// + /// Load a wav file into the stream to be played. + /// + public void LoadWavFromFileToStream(string p) + { + // Create a new SpriteBatch, which can be used to draw textures. + + string file =p; + System.IO.Stream waveFileStream = File.OpenRead(file); //TitleContainer.OpenStream(file); + + BinaryReader reader = new BinaryReader(waveFileStream); + + int chunkID = reader.ReadInt32(); + int fileSize = reader.ReadInt32(); + int riffType = reader.ReadInt32(); + int fmtID = reader.ReadInt32(); + int fmtSize = reader.ReadInt32(); + int fmtCode = reader.ReadInt16(); + int channels = reader.ReadInt16(); + int sampleRate = reader.ReadInt32(); + int fmtAvgBPS = reader.ReadInt32(); + int fmtBlockAlign = reader.ReadInt16(); + int bitDepth = reader.ReadInt16(); + + if (fmtSize == 18) + { + // Read any extra values + int fmtExtraSize = reader.ReadInt16(); + reader.ReadBytes(fmtExtraSize); + } + + int dataID = reader.ReadInt32(); + int dataSize = reader.ReadInt32(); + + byteArray = reader.ReadBytes(dataSize); + + dynamicSound = new DynamicSoundEffectInstance(sampleRate, (AudioChannels)channels); + count = dynamicSound.GetSampleSizeInBytes(TimeSpan.FromMilliseconds(100)); + + dynamicSound.BufferNeeded += new EventHandler(DynamicSound_BufferNeeded); + this.currentSong = new Song(p); + } + + void DynamicSound_BufferNeeded(object sender, EventArgs e) + { + dynamicSound.SubmitBuffer(byteArray, position, count / 2); + dynamicSound.SubmitBuffer(byteArray, position + count / 2, count / 2); + + position += count; + if (position + count > byteArray.Length) + { + position = 0; + } + } + + /// /// Returns the name of the currently playing song. /// /// public override string getNameOfCurrentSong() { + if (this.currentSong == null) return ""; return this.currentSong.name; } @@ -79,30 +155,86 @@ namespace StardewSymphonyRemastered.Framework this.songInformation.listOfSongsWithoutTriggers = listOfSongs; } + /// + /// Used to pause the current song. + /// public override void pauseSong() { - throw new NotImplementedException(); + if (dynamicSound != null) dynamicSound.Pause(); } + /// + /// Used to play a song. + /// + /// public override void playSong(string name) { - throw new NotImplementedException(); + string pathToSong = getSongPathFromName(name); + LoadWavFromFileToStream(pathToSong); + dynamicSound.Play(); } + /// + /// Used to resume the currently playing song. + /// public override void resumeSong() { - throw new NotImplementedException(); + if (dynamicSound == null) return; + dynamicSound.Resume(); } + /// + /// Used to stop the currently playing song. + /// public override void stopSong() { - throw new NotImplementedException(); + if (dynamicSound != null) + { + dynamicSound.Stop(); + dynamicSound = null; + this.currentSong = null; + } } + /// + /// Used to change from one playing song to another; + /// + /// public override void swapSong(string songName) { - throw new NotImplementedException(); + this.stopSong(); + this.playSong(songName); } + /// + /// Get the son's name from the path. + /// + /// + /// + public string getSongNameFromPath(string path) + { + foreach(var song in this.songInformation.listOfSongsWithoutTriggers) + { + if (song.pathToSong == path) return song.name; + } + return ""; + } + + /// + /// Gets the song's path that shares the same name. + /// + /// + /// + public string getSongPathFromName(string name) + { + foreach (var song in this.songInformation.listOfSongsWithoutTriggers) + { + if (song.name == name) return song.pathToSong; + } + return ""; + } + + + } } diff --git a/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/StardewSymphony.cs b/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/StardewSymphony.cs index dd73bdb3..02c31a83 100644 --- a/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/StardewSymphony.cs +++ b/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/StardewSymphony.cs @@ -56,6 +56,7 @@ namespace StardewSymphonyRemastered StardewModdingAPI.Events.SaveEvents.AfterLoad += SaveEvents_AfterLoad; StardewModdingAPI.Events.LocationEvents.CurrentLocationChanged += LocationEvents_CurrentLocationChanged; StardewModdingAPI.Events.GameEvents.UpdateTick += GameEvents_UpdateTick; + StardewModdingAPI.Events.ControlEvents.KeyPressed += ControlEvents_KeyPressed; musicManager = new MusicManager(); MusicPath = Path.Combine(ModHelper.DirectoryPath, "Content", "Music"); @@ -66,9 +67,19 @@ namespace StardewSymphonyRemastered this.createDirectories(); this.createBlankXACTTemplate(); this.createBlankWAVTemplate(); + musicPacksInitialized = false; } + private void ControlEvents_KeyPressed(object sender, StardewModdingAPI.Events.EventArgsKeyPressed e) + { + if (e.KeyPressed == Microsoft.Xna.Framework.Input.Keys.O) + { + Game1.activeClickableMenu = new StardewSymphonyRemastered.Framework.Menus.MusicManagerMenu(); + } + } + + /// /// Raised every frame. Mainly used just to initiate the music packs. Probably not needed. /// @@ -80,6 +91,7 @@ namespace StardewSymphonyRemastered { initializeMusicPacks(); musicPacksInitialized = true; + musicManager.selectMusic(SongSpecifics.getCurrentConditionalString()); } } @@ -241,6 +253,7 @@ namespace StardewSymphonyRemastered StardewSymphonyRemastered.Framework.SongSpecifics.addLocations(); StardewSymphonyRemastered.Framework.SongSpecifics.addFestivals(); StardewSymphonyRemastered.Framework.SongSpecifics.addEvents(); + musicManager.initializeSeasonalMusic(); } diff --git a/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/StardewSymphonyRemastered.csproj b/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/StardewSymphonyRemastered.csproj index 65480488..0e523462 100644 --- a/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/StardewSymphonyRemastered.csproj +++ b/GeneralMods/StardewSymphonyRemastered/StardewSymphonyRemastered/StardewSymphonyRemastered.csproj @@ -42,6 +42,7 @@ +