using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Microsoft.Xna.Framework.Audio;
using StardewModdingAPI;
using StardewValley;
namespace Omegasis.StardewSymphony.Framework
{
/// Data and metadata for a music pack.
internal class MusicManager
{
/*********
** Properties
*********/
/// Writes messages to the console and log file.
private readonly IMonitor Monitor;
/// The valid season values.
private readonly Season[] Seasons = Enum.GetValues(typeof(Season)).Cast().ToArray();
/*********
** Accessors
*********/
/// The directory path containing the music.
public string Directory { get; }
/// The name of the wavebank file.
public string WavebankName { get; }
/// The name of the soundbank file.
public string SoundbankName { get; }
/// The loaded wavebank (if any).
public WaveBank Wavebank { get; }
/// The loaded soundbank (if any).
public SoundBank Soundbank { get; }
/// The default music to play if there isn't a more specific option.
public IDictionary> DefaultSongs = MusicManager.CreateSeasonalSongList();
/// The music to play at night.
public IDictionary> NightSongs = MusicManager.CreateSeasonalSongList();
/// The music to play on rainy days.
public IDictionary> RainySongs = MusicManager.CreateSeasonalSongList();
/// The music to play on rainy nights.
public IDictionary> RainyNightSongs = MusicManager.CreateSeasonalSongList();
/// Songs that play in specific locations.
public Dictionary> LocationSongs { get; } = new Dictionary>();
/// Songs that play in specific locations on rainy days.
public Dictionary> LocationRainSongs { get; } = new Dictionary>();
/// Songs that play in specific locations at night.
public Dictionary> LocationNightSongs { get; } = new Dictionary>();
/// Songs that play in specific locations on rainy nights.
public Dictionary> LocationRainNightSongs { get; } = new Dictionary>();
/*********
** Public methods
*********/
/// Construct an instance.
/// Writes messages to the console and log file.
/// The name of the wavebank file.
/// The name of the soundbank file.
/// The directory path containing the music.
public MusicManager(IMonitor monitor, string wavebank, string soundbank, string directory)
{
// init data
this.Monitor = monitor;
this.Directory = directory;
this.WavebankName = wavebank + ".xwb";
this.SoundbankName = soundbank + ".xsb";
// init banks
string wavePath = Path.Combine(this.Directory, this.WavebankName);
string soundPath = Path.Combine(this.Directory, this.SoundbankName);
this.Monitor.Log(wavePath);
this.Monitor.Log(soundPath);
if (File.Exists(wavePath))
this.Wavebank = new WaveBank(Game1.audioEngine, wavePath);
if (File.Exists(Path.Combine(this.Directory, this.SoundbankName)))
this.Soundbank = new SoundBank(Game1.audioEngine, soundPath);
// update audio
Game1.audioEngine.Update();
}
/// Read cue names from a text file and adds them to a specific list. Morphs with specific conditional name. Conditionals are hardcoded.
/// The conditional file name to read.
/// The music list to update.
public void LoadSeasonalSongs(string conditionalName, IDictionary cues)
{
string path = Path.Combine(this.Directory, "Music_Files", "Seasons", conditionalName + ".txt");
if (!File.Exists(path))
{
this.Monitor.Log($"Stardew Symohony:The specified music file could not be found. That music file is {conditionalName} which should be located at {path} but don't worry I'll create it for you right now. It's going to be blank though");
string[] text = new string[3];
text[0] = conditionalName + " music file. This file holds all of the music that will play when there is no music for this game location, or simply put this is default music. Simply type the name of the song below the wall of equal signs.";
text[1] = "========================================================================================";
File.WriteAllLines(path, text);
}
else
{
this.Monitor.Log($"Stardew Symphony:The music pack located at: {this.Directory} is processing the song info for the game location: {conditionalName}");
string[] text = File.ReadAllLines(path);
int i = 2;
var lineCount = File.ReadLines(path).Count();
while (i < lineCount) //the ordering seems bad, but it works.
{
if (Convert.ToString(text[i]) == "")
break;
if (Convert.ToString(text[i]) == "\n")
break;
foreach (Season season in this.Seasons)
{
// default music
if ($"{season}".Equals(conditionalName, StringComparison.InvariantCultureIgnoreCase))
{
string cueName = Convert.ToString(text[i]);
i++;
this.DefaultSongs[season].Add(this.Soundbank.GetCue(cueName));
if (!cues.Keys.Contains(cueName))
cues.Add(cueName, this);
}
// night music
if ($"{season}_night".Equals(conditionalName, StringComparison.InvariantCultureIgnoreCase))
{
string cueName = Convert.ToString(text[i]);
i++;
this.NightSongs[season].Add(this.Soundbank.GetCue(cueName));
if (!cues.Keys.Contains(cueName))
cues.Add(cueName, this);
}
// rain music
if ($"{season}_rain".Equals(conditionalName, StringComparison.InvariantCultureIgnoreCase))
{
string cueName = Convert.ToString(text[i]);
i++;
this.RainySongs[season].Add(this.Soundbank.GetCue(cueName));
if (!cues.Keys.Contains(cueName))
cues.Add(cueName, this);
}
// rainy night
if ($"{season}_rain_night".Equals(conditionalName, StringComparison.InvariantCultureIgnoreCase))
{
string cueName = Convert.ToString(text[i]);
i++;
this.RainyNightSongs[season].Add(this.Soundbank.GetCue(cueName));
if (!cues.Keys.Contains(cueName))
cues.Add(cueName, this);
}
}
}
if (i == 2)
{
// Monitor.Log("Just thought that I'd let you know that there are no songs associated with the music file located at " + mylocation3 +" this may be intentional, but just incase you were wanted music, now you knew which ones were blank.");
return;
}
this.Monitor.Log($"Stardew Symohony:The music pack located at: {this.Directory} has successfully processed the song info for the game location {conditionalName}");
}
}
/// Read cue names from a text file and adds them to a specific list. Morphs with specific conditional name. Conditionals are hardcoded.
/// The conditional file name to read.
/// The music list to update.
public void Music_Loader_Locations(string conditionalName, IDictionary cues)
{
List locationSongs = new List();
string path = Path.Combine(this.Directory, "Music_Files", "Locations", conditionalName + ".txt");
if (!File.Exists(path))
{
this.Monitor.Log("StardewSymohony:A music list for the location " + conditionalName + " does not exist for the music pack located at " + path + " which isn't a problem, I just thought I'd let you know since this may have been intentional. Also I'm creating it for you just incase. Cheers.");
string[] text = new string[3];//seems legit.
text[0] = conditionalName + " music file. This file holds all of the music that will play when at this game location. Simply type the name of the song below the wall of equal signs.";
text[1] = "========================================================================================";
File.WriteAllLines(path, text);
}
else
{
this.Monitor.Log("Stardew Symphony:The music pack located at: " + this.Directory + " is processing the song info for the game location: " + conditionalName);
string[] readtext = File.ReadAllLines(path);
int i = 2;
var lineCount = File.ReadLines(path).Count();
while (i < lineCount) //the ordering seems bad, but it works.
{
if (Convert.ToString(readtext[i]) == "")
break;
if (Convert.ToString(readtext[i]) == "\n")
break;
string cueName = Convert.ToString(readtext[i]);
i++;
if (!cues.Keys.Contains(cueName))
{
locationSongs.Add(this.Soundbank.GetCue(cueName));
cues.Add(cueName, this);
}
else
locationSongs.Add(this.Soundbank.GetCue(cueName));
}
if (i == 2)
{
// Monitor.Log("Just thought that I'd let you know that there are no songs associated with the music file located at " + mylocation3 + " this may be intentional, but just incase you were wanted music, now you knew which ones were blank.");
return;
}
if (locationSongs.Count > 0)
{
this.LocationSongs.Add(conditionalName, locationSongs);
this.Monitor.Log("StardewSymhony:The music pack located at: " + this.Directory + " has successfully processed the song info for the game location: " + conditionalName);
}
}
}
/// Read cue names from a text file and adds them to a specific list. Morphs with specific conditional name. Conditionals are hardcoded.
/// The conditional file name to read.
/// The music list to update.
public void Music_Loader_Locations_Rain(string conditionalName, IDictionary cues)
{
List locationSongs = new List();
string path = Path.Combine(this.Directory, "Music_Files", "Locations", conditionalName + ".txt");
if (!File.Exists(path))
{
this.Monitor.Log("StardewSymphony:A music list for the location " + conditionalName + " does not exist for the music pack located at " + path + " which isn't a problem, I just thought I'd let you know since this may have been intentional. Also I'm creating it for you just incase. Cheers.");
string[] text = new string[3];//seems legit.
text[0] = conditionalName + " music file. This file holds all of the music that will play when at this game location. Simply type the name of the song below the wall of equal signs.";
text[1] = "========================================================================================";
File.WriteAllLines(path, text);
}
else
{
// add in data here
string[] readtext = File.ReadAllLines(path);
int i = 2;
var lineCount = File.ReadLines(path).Count();
while (i < lineCount) //the ordering seems bad, but it works.
{
if (Convert.ToString(readtext[i]) == "")
break;
if (Convert.ToString(readtext[i]) == "\n")
break;
string cueName = Convert.ToString(readtext[i]);
i++;
if (!cues.Keys.Contains(cueName))
{
locationSongs.Add(this.Soundbank.GetCue(cueName));
cues.Add(cueName, this);
}
else
locationSongs.Add(this.Soundbank.GetCue(cueName));
}
if (i == 2)
{
// Monitor.Log("Just thought that I'd let you know that there are no songs associated with the music file located at " + mylocation3 + " this may be intentional, but just incase you were wanted music, now you knew which ones were blank.");
return;
}
if (locationSongs.Count > 0)
{
this.LocationRainSongs.Add(conditionalName, locationSongs);
this.Monitor.Log("StardewSymohony:The music pack located at: " + this.Directory + " has successfully processed the song info for the game location: " + conditionalName);
}
}
}
/// Read cue names from a text file and adds them to a specific list. Morphs with specific conditional name. Conditionals are hardcoded.
/// The conditional file name to read.
/// The music list to update.
public void Music_Loader_Locations_Night(string conditionalName, IDictionary cues)
{
List locationSongs = new List();
string path = Path.Combine(this.Directory, "Music_Files", "Locations", conditionalName + ".txt");
if (!File.Exists(path))
{
this.Monitor.Log("StardewSymphony:A music list for the location " + conditionalName + " does not exist for the music pack located at " + path + " which isn't a problem, I just thought I'd let you know since this may have been intentional. Also I'm creating it for you just incase. Cheers.");
string[] text = new string[3];//seems legit.
text[0] = conditionalName + " music file. This file holds all of the music that will play when at this game location. Simply type the name of the song below the wall of equal signs.";
text[1] = "========================================================================================";
File.WriteAllLines(path, text);
}
else
{
// add in data here
string[] readtext = File.ReadAllLines(path);
int i = 2;
var lineCount = File.ReadLines(path).Count();
while (i < lineCount) //the ordering seems bad, but it works.
{
if (Convert.ToString(readtext[i]) == "")
break;
if (Convert.ToString(readtext[i]) == "\n")
break;
string cueName = Convert.ToString(readtext[i]);
i++;
if (!cues.Keys.Contains(cueName))
{
locationSongs.Add(this.Soundbank.GetCue(cueName));
cues.Add(cueName, this);
}
else
locationSongs.Add(this.Soundbank.GetCue(cueName));
}
if (i == 2)
{
// Monitor.Log("Just thought that I'd let you know that there are no songs associated with the music file located at " + mylocation3 + " this may be intentional, but just incase you were wanted music, now you knew which ones were blank.");
return;
}
if (locationSongs.Count > 0)
{
this.LocationNightSongs.Add(conditionalName, locationSongs);
this.Monitor.Log("StardewSymphonyLThe music pack located at: " + this.Directory + " has successfully processed the song info for the game location: " + conditionalName);
}
}
}
/// Read cue names from a text file and adds them to a specific list. Morphs with specific conditional name. Conditionals are hardcoded.
/// The conditional file name to read.
/// The music list to update.
public void Music_Loader_Locations_Rain_Night(string conditionalName, IDictionary cues)
{
List locationSongs = new List();
var musicPath = this.Directory;
string path = Path.Combine(musicPath, "Music_Files", "Locations", conditionalName + ".txt");
if (!File.Exists(path))
{
this.Monitor.Log("StardewSymphony:A music list for the location " + conditionalName + " does not exist for the music pack located at " + path + " which isn't a problem, I just thought I'd let you know since this may have been intentional. Also I'm creating it for you just incase. Cheers.");
string[] text = new string[3];//seems legit.
text[0] = conditionalName + " music file. This file holds all of the music that will play when at this game location. Simply type the name of the song below the wall of equal signs.";
text[1] = "========================================================================================";
File.WriteAllLines(path, text);
}
else
{
//load in music stuff from the text files using the code below.
string[] text = File.ReadAllLines(path);
int i = 2;
var lineCount = File.ReadLines(path).Count();
while (i < lineCount) //the ordering seems bad, but it works.
{
if (Convert.ToString(text[i]) == "") //if there is ever an empty line, stop processing the music file
break;
if (Convert.ToString(text[i]) == "\n")
break;
string cueName = Convert.ToString(text[i]);
i++;
if (!cues.Keys.Contains(cueName))
{
locationSongs.Add(this.Soundbank.GetCue(cueName));
cues.Add(cueName, this);
}
else
locationSongs.Add(this.Soundbank.GetCue(cueName));
}
if (i == 2)
{
// Monitor.Log("Just thought that I'd let you know that there are no songs associated with the music file located at " + mylocation3 + " this may be intentional, but just incase you were wanted music, now you knew which ones were blank.");
return;
}
if (locationSongs.Count > 0)
{
this.LocationRainNightSongs.Add(conditionalName, locationSongs);
this.Monitor.Log("StardewSymohony:The music pack located at: " + this.Directory + " has successfully processed the song info for the game location: " + conditionalName);
}
}
}
/// Create a dictionary of seasonal songs.
private static IDictionary> CreateSeasonalSongList()
{
IDictionary> dict = new Dictionary>();
foreach (Season season in Enum.GetValues(typeof(Season)))
dict[season] = new List();
return dict;
}
}
}