diff --git a/GeneralMods/SimpleSoundManager/SimpleSoundManager.csproj b/GeneralMods/SimpleSoundManager/SimpleSoundManager.csproj index bde471b6..746852c3 100644 --- a/GeneralMods/SimpleSoundManager/SimpleSoundManager.csproj +++ b/GeneralMods/SimpleSoundManager/SimpleSoundManager.csproj @@ -74,7 +74,11 @@ + + + + diff --git a/GeneralMods/SimpleSoundManager/Sound.cs b/GeneralMods/SimpleSoundManager/Sound.cs new file mode 100644 index 00000000..33fe9088 --- /dev/null +++ b/GeneralMods/SimpleSoundManager/Sound.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SimpleSoundManager +{ + /// + /// Interface used for common sound functionality; + /// + public interface Sound + { + /// + /// Handles playing a sound. + /// + void play(); + /// + /// Handles pausing a song. + /// + void pause(); + /// + /// Handles stopping a song. + /// + void stop(); + /// + /// Handles restarting a song. + /// + void restart(); + /// + /// Handles getting a clone of the song. + /// + /// + Sound clone(); + } +} diff --git a/GeneralMods/SimpleSoundManager/SoundManager.cs b/GeneralMods/SimpleSoundManager/SoundManager.cs index b0e07ef1..e60d811d 100644 --- a/GeneralMods/SimpleSoundManager/SoundManager.cs +++ b/GeneralMods/SimpleSoundManager/SoundManager.cs @@ -9,200 +9,124 @@ using System.Threading.Tasks; namespace SimpleSoundManager { - public class SoundManager + class SoundManager { - public WaveBank waveBank; - public ISoundBank soundBank; - WaveBank vanillaWaveBank; - ISoundBank vanillaSoundBank; - List currentlyPlayingSounds; + + public Dictionary sounds; + public Dictionary musicBanks; + /// - /// Make a new Sound Manager to play and manage sounds in a modded wave bank. + /// Constructor for this class. /// - /// The path to the wave bank in the mod's asset folder. - /// The path to the sound bank in the mod's asset folder. - public SoundManager(string newWaveBank, string newSoundBank) + public SoundManager() { - this.waveBank = new WaveBank(Game1.audioEngine, newWaveBank); - - this.soundBank = (ISoundBank)new SoundBankWrapper(new SoundBank(Game1.audioEngine, newSoundBank)); - this.currentlyPlayingSounds = new List(); - vanillaWaveBank = Game1.waveBank; - vanillaSoundBank = Game1.soundBank; + this.sounds = new Dictionary(); + this.musicBanks = new Dictionary(); } /// - /// Make a new Sound Manager to play and manage sounds in a modded wave bank. - /// - /// The reference to the wave bank in the mod's asset folder. - /// The reference to the sound bank in the mod's asset folder. - public SoundManager(WaveBank newWaveBank, ISoundBank newSoundBank) - { - this.waveBank = newWaveBank; - this.soundBank = newSoundBank; - this.currentlyPlayingSounds = new List(); - } - - /// - /// Play a sound from the mod's wave bank. - /// - /// The name of the sound in the mod's wave bank. This will fail if the sound doesn't exists. This is also case sensitive. - public void playSound(string soundName) - { - Game1.waveBank = this.waveBank; - Game1.soundBank = this.soundBank; - - Cue currentCue = this.soundBank.GetCue(soundName); - if (currentCue == null) return; - else - { - currentCue.Play(); - currentlyPlayingSounds.Add(currentCue); - } - - Game1.waveBank = this.vanillaWaveBank; - Game1.soundBank = this.vanillaSoundBank; - removeAllStopedSounds(); - } - - /// - /// Pauses the first instance of this sound. + /// Constructor for wav files. /// /// - public void pauseSound(string soundName) + /// + public void loadWavFile(string soundName,string pathToWav) { - foreach (var v in currentlyPlayingSounds) - { - if (v.Name == soundName) v.Pause(); - break; - } - removeAllStopedSounds(); + WavSound wav = new WavSound(pathToWav); + this.sounds.Add(soundName,wav); } - + /// - /// Pause all sounds that share the sound name in common. + /// Constructor for wav files. /// + /// /// - public void pauseAllSoundsWithThisName(string soundName) + /// + public void loadWavFile(IModHelper helper,string soundName,string pathToWav) { - foreach (var v in currentlyPlayingSounds) - { - if (v.Name == soundName) v.Pause(); - } - removeAllStopedSounds(); + WavSound wav = new WavSound(helper ,pathToWav); + this.sounds.Add(soundName,wav); } /// - /// Pauses all of the sounds that the SoundManager class is keeping track of. + /// Constructor for wav files. /// - public void pauseAllSounds() + /// + /// + /// + public void loadWavFile(IModHelper helper,string songName,List pathToWav) { - foreach(var v in currentlyPlayingSounds) - { - v.Pause(); - } - removeAllStopedSounds(); + WavSound wav = new WavSound(helper,pathToWav); + this.sounds.Add(songName,wav); } /// - /// Resume the first instance of the sound that has this name. + /// Constructor for XACT files. /// - public void resumeSound(string soundName) + /// + /// + /// + public void loadXACTFile(WaveBank waveBank, ISoundBank soundBank, string songName) { - foreach(var v in currentlyPlayingSounds) - { - if (v.Name==soundName&&v.IsPaused) v.Resume(); - break; - } - removeAllStopedSounds(); + XACTSound xactSound = new XACTSound(waveBank, soundBank, songName); + this.sounds.Add(songName, xactSound); } /// - /// Resume all paused sounds that have this name. + /// Constructor for XACT files based on already added music packs. /// - /// - public void resumeAllSoundsWithThisName(string soundName) + /// + /// + public void loadXACTFile(string pairName, string songName) { - foreach (var v in currentlyPlayingSounds) + XACTMusicPair musicPair = getMusicPack(pairName); + if (pairName == null) { - if (v.Name == soundName && v.IsPaused) v.Resume(); + return; } - removeAllStopedSounds(); + loadXACTFile(musicPair.waveBank, musicPair.soundBank, songName); + } + + + /// + /// Creates a music pack pair that holds .xwb and .xsb music files. + /// + /// The mod's helper that will handle the path of the files. + /// The name of this music pack pair. + /// The relative path to the .xwb file + /// The relative path to the .xsb file + public void loadXACTMusicBank(IModHelper helper,string pairName,string wavName, string soundName) + { + this.musicBanks.Add(pairName,new XACTMusicPair(helper, wavName, soundName)); } /// - /// Resumes playing all paused sounds. + /// Gets the music pack pair from the sound pool. /// - public void resumeAllSounds() + /// + /// + public XACTMusicPair getMusicPack(string name) { - foreach (var v in currentlyPlayingSounds) + foreach(var pack in this.musicBanks) { - if (v.IsPaused) v.Resume(); + if (name == pack.Key) return pack.Value; } - removeAllStopedSounds(); + return null; } /// - /// Stop the first instance of the sound that has this name. + /// Gets a clone of the loaded sound. /// - /// - public void stopSound(string soundName) + /// + /// + public Sound getSoundClone(string name) { - foreach (var v in currentlyPlayingSounds) + foreach(var sound in this.sounds) { - if (v.Name == soundName) - { - v.Stop(AudioStopOptions.Immediate); - break; - } + if (sound.Key == name) return sound.Value.clone(); } - removeAllStopedSounds(); + return null; } - /// - /// Stops all of the sounds that share this name. - /// - /// - public void stopAllSoundsWithThisName(string soundName) - { - foreach (var v in currentlyPlayingSounds) - { - if (v.Name == soundName) - { - v.Stop(AudioStopOptions.Immediate); - } - } - removeAllStopedSounds(); - } - - /// - /// Stops all of the sounds that the SoundManager is keeping track of. - /// - public void stopAllSounds() - { - foreach(var v in currentlyPlayingSounds) - { - v.Stop(AudioStopOptions.Immediate); - } - removeAllStopedSounds(); - } - - /// - /// Removes all of the sounds that have stoped playing. Used to clean up the list of songs that SoundManager is keeping track of, whether the sound is finished or it manually was stopped. - /// - public void removeAllStopedSounds() - { - List cuesToRemove = new List(); - foreach (var v in currentlyPlayingSounds) - { - if (v.IsStopped) cuesToRemove.Add(v); - } - foreach (var v in cuesToRemove) - { - currentlyPlayingSounds.Remove(v); - } - cuesToRemove.Clear(); - } } } diff --git a/GeneralMods/SimpleSoundManager/WavSound.cs b/GeneralMods/SimpleSoundManager/WavSound.cs new file mode 100644 index 00000000..3c42ef29 --- /dev/null +++ b/GeneralMods/SimpleSoundManager/WavSound.cs @@ -0,0 +1,236 @@ +using Microsoft.Xna.Framework.Audio; +using StardewModdingAPI; +using StardewValley; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SimpleSoundManager +{ + class WavSound : Sound + { + + /// + /// 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; + + public List sounds; + + public string path; + + + + /// + /// Get a raw disk path to the wav file. + /// + /// + public WavSound(string pathToWavFile) + { + this.path = pathToWavFile; + LoadWavFromFileToStream(); + } + + /// + /// A constructor that takes a mod helper and a relative path to a wav file. + /// + /// + /// + public WavSound(IModHelper modHelper, string pathInModDirectory) + { + string path = Path.Combine(modHelper.DirectoryPath, pathInModDirectory); + this.path = path; + } + + /// + /// Constructor that is more flexible than typing an absolute path. + /// + /// The mod helper for the mod you wish to use to load the music files from. + /// The list of folders and files that make up a complete path. + public WavSound(IModHelper modHelper, List pathPieces) + { + string s = modHelper.DirectoryPath; + foreach(var str in pathPieces) + { + s = Path.Combine(s, str); + } + this.path = s; + } + + /// + /// Loads the .wav file from disk and plays it. + /// + public void LoadWavFromFileToStream() + { + // Create a new SpriteBatch, which can be used to draw textures. + + string file = this.path; + 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(10000)); + + } + + void DynamicSound_BufferNeeded(object sender, EventArgs e) + { + try + { + dynamicSound.SubmitBuffer(byteArray, position, count); + } + catch (Exception err) + { + + } + + position += count; + if (position + count > byteArray.Length) + { + position = 0; + } + } + + /// + /// Used to pause the current song. + /// + public void pause() + { + if (dynamicSound != null) dynamicSound.Pause(); + } + + /// + /// Used to play a song. + /// + /// + public void play() + { + if (this.isPlaying() == true) return; + dynamicSound.BufferNeeded += new EventHandler(DynamicSound_BufferNeeded); + dynamicSound.Play(); + } + + + /// + /// Used to resume the currently playing song. + /// + public void resume() + { + if (dynamicSound == null) return; + dynamicSound.Resume(); + } + + /// + /// Used to stop the currently playing song. + /// + public void stop() + { + + if (dynamicSound != null) + { + dynamicSound.Stop(true); + dynamicSound.BufferNeeded -= new EventHandler(DynamicSound_BufferNeeded); + position = 0; + count = 0; + byteArray = new byte[0]; + } + } + + /// + /// Used to change from one playing song to another; + /// + /// + public void swap(string pathToNewWavFile) + { + this.stop(); + this.path = pathToNewWavFile; + this.play(); + } + + /// + /// Checks if the song is currently playing. + /// + /// + public bool isPlaying() + { + if (this.dynamicSound == null) return false; + if (this.dynamicSound.State == SoundState.Playing) return true; + else return false; + } + + /// + /// Checks if the song is currently paused. + /// + /// + public bool isPaused() + { + if (this.dynamicSound == null) return false; + if (this.dynamicSound.State == SoundState.Paused) return true; + else return false; + } + + /// + /// Checks if the song is currently stopped. + /// + /// + public bool isStopped() + { + if (this.dynamicSound == null) return false; + if (this.dynamicSound.State == SoundState.Stopped) return true; + else return false; + } + + public Sound clone() + { + return new WavSound(this.path); + } + + public void restart() + { + this.stop(); + this.play(); + } + + } +} diff --git a/GeneralMods/SimpleSoundManager/XACTSound.cs b/GeneralMods/SimpleSoundManager/XACTSound.cs new file mode 100644 index 00000000..b486017a --- /dev/null +++ b/GeneralMods/SimpleSoundManager/XACTSound.cs @@ -0,0 +1,134 @@ +using Microsoft.Xna.Framework.Audio; +using StardewModdingAPI; +using StardewValley; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SimpleSoundManager +{ + public class XACTSound : Sound + { + public WaveBank waveBank; + public ISoundBank soundBank; + public string soundName; + WaveBank vanillaWaveBank; + ISoundBank vanillaSoundBank; + Cue song; + + /// + /// Make a new Sound Manager to play and manage sounds in a modded wave bank. + /// + /// The reference to the wave bank in the mod's asset folder. + /// The reference to the sound bank in the mod's asset folder. + public XACTSound(WaveBank newWaveBank, ISoundBank newSoundBank,string soundName) + { + this.waveBank = newWaveBank; + this.soundBank = newSoundBank; + + vanillaSoundBank = Game1.soundBank; + vanillaWaveBank = Game1.waveBank; + this.soundName = soundName; + song = this.soundBank.GetCue(this.soundName); + } + + /// + /// Play a sound from the mod's wave bank. + /// + /// The name of the sound in the mod's wave bank. This will fail if the sound doesn't exists. This is also case sensitive. + public void play(string soundName) + { + Game1.waveBank = this.waveBank; + Game1.soundBank = this.soundBank; + + if (this.song == null) return; + + this.song.Play(); + + Game1.waveBank = this.vanillaWaveBank; + Game1.soundBank = this.vanillaSoundBank; + } + + /// + /// Pauses the first instance of this sound. + /// + /// + public void pause(string soundName) + { + if (this.song == null) return; + this.song.Pause(); + } + + /// + /// Resume the first instance of the sound that has this name. + /// + public void resume(string soundName) + { + if (this.song == null) return; + this.song.Resume(); + } + + + /// + /// Stop the first instance of the sound that has this name. + /// + /// + public void stop(string soundName) + { + if (this.song == null) return; + this.song.Stop(AudioStopOptions.Immediate); + } + + /// + /// Resumes a paused song. + /// + public void resume() + { + this.resume(soundName); + } + + /// + /// Plays this song. + /// + public void play() + { + this.play(this.soundName); + } + + /// + /// Pauses this song. + /// + public void pause() + { + this.pause(this.soundName); + } + + /// + /// Stops this somg. + /// + public void stop() + { + this.stop(this.soundName); + } + + /// + /// Restarts this song. + /// + public void restart() + { + this.stop(); + this.play(); + } + + /// + /// Gets a clone of this song. + /// + /// + public Sound clone() + { + return new XACTSound(this.waveBank, this.soundBank, this.soundName); + } + } +} diff --git a/GeneralMods/SimpleSoundManager/XactMusicPair.cs b/GeneralMods/SimpleSoundManager/XactMusicPair.cs new file mode 100644 index 00000000..999a34af --- /dev/null +++ b/GeneralMods/SimpleSoundManager/XactMusicPair.cs @@ -0,0 +1,34 @@ +using Microsoft.Xna.Framework.Audio; +using StardewModdingAPI; +using StardewValley; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SimpleSoundManager +{ + class XACTMusicPair + { + public WaveBank waveBank; + public ISoundBank soundBank; + + /// + /// Create a xwb and xsb music pack pair. + /// + /// The mod helper from the mod that will handle loading in the file. + /// A relative path to the .xwb file in the mod helper's mod directory. + /// A relative path to the .xsb file in the mod helper's mod directory. + public XACTMusicPair(IModHelper helper,string wavBankPath, string soundBankPath) + { + wavBankPath = Path.Combine(helper.DirectoryPath, wavBankPath); + soundBankPath = Path.Combine(helper.DirectoryPath, soundBankPath); + + + waveBank = new WaveBank(Game1.audioEngine, wavBankPath); + soundBank = new SoundBankWrapper(new SoundBank(Game1.audioEngine, soundBankPath)); + } + } +} diff --git a/GeneralMods/SimpleSoundManager/manifest.json b/GeneralMods/SimpleSoundManager/manifest.json index d11b436a..9f93e023 100644 --- a/GeneralMods/SimpleSoundManager/manifest.json +++ b/GeneralMods/SimpleSoundManager/manifest.json @@ -1,7 +1,7 @@ { "Name": "Simple Sound Manager", "Author": "Alpha_Omegasis", - "Version": "1.0.1", + "Version": "2.0.0", "Description": "A simple framework to play sounds from wave banks.", "UniqueID": "Omegasis.SimpleSoundManager", "EntryDll": "SimpleSoundManager.dll",