2018-06-01 05:38:24 +08:00
|
|
|
|
using Microsoft.Xna.Framework.Audio;
|
2018-08-06 00:33:00 +08:00
|
|
|
|
using SimpleSoundManager.Framework;
|
2018-06-01 05:38:24 +08:00
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Used to actually play the song.
|
|
|
|
|
/// </summary>
|
|
|
|
|
DynamicSoundEffectInstance dynamicSound;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Used to keep track of where in the song we are.
|
|
|
|
|
/// </summary>
|
|
|
|
|
int position;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// ???
|
|
|
|
|
/// </summary>
|
|
|
|
|
int count;
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Used to store the info for the song.
|
|
|
|
|
/// </summary>
|
|
|
|
|
byte[] byteArray;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public string path;
|
|
|
|
|
|
2018-08-07 05:01:44 +08:00
|
|
|
|
public string soundName;
|
2018-06-01 05:38:24 +08:00
|
|
|
|
|
2018-08-16 14:59:39 +08:00
|
|
|
|
|
|
|
|
|
public bool loop;
|
|
|
|
|
|
2018-06-01 05:38:24 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Get a raw disk path to the wav file.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="pathToWavFile"></param>
|
2018-08-16 14:59:39 +08:00
|
|
|
|
public WavSound(string name,string pathToWavFile,bool Loop=false)
|
2018-06-01 05:38:24 +08:00
|
|
|
|
{
|
|
|
|
|
this.path = pathToWavFile;
|
|
|
|
|
LoadWavFromFileToStream();
|
2018-08-07 05:01:44 +08:00
|
|
|
|
this.soundName = name;
|
2018-08-16 14:59:39 +08:00
|
|
|
|
this.loop = Loop;
|
2018-06-01 05:38:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// A constructor that takes a mod helper and a relative path to a wav file.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="modHelper"></param>
|
|
|
|
|
/// <param name="pathInModDirectory"></param>
|
2018-08-16 14:59:39 +08:00
|
|
|
|
public WavSound(IModHelper modHelper,string name, string pathInModDirectory,bool Loop=false)
|
2018-06-01 05:38:24 +08:00
|
|
|
|
{
|
|
|
|
|
string path = Path.Combine(modHelper.DirectoryPath, pathInModDirectory);
|
|
|
|
|
this.path = path;
|
2018-08-07 05:01:44 +08:00
|
|
|
|
this.soundName = name;
|
2018-08-16 14:59:39 +08:00
|
|
|
|
this.loop = Loop;
|
2018-06-01 05:38:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Constructor that is more flexible than typing an absolute path.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="modHelper">The mod helper for the mod you wish to use to load the music files from.</param>
|
|
|
|
|
/// <param name="pathPieces">The list of folders and files that make up a complete path.</param>
|
2018-08-16 14:59:39 +08:00
|
|
|
|
public WavSound(IModHelper modHelper,string soundName, List<string> pathPieces,bool Loop=false)
|
2018-06-01 05:38:24 +08:00
|
|
|
|
{
|
|
|
|
|
string s = modHelper.DirectoryPath;
|
|
|
|
|
foreach(var str in pathPieces)
|
|
|
|
|
{
|
|
|
|
|
s = Path.Combine(s, str);
|
|
|
|
|
}
|
|
|
|
|
this.path = s;
|
2018-08-07 05:01:44 +08:00
|
|
|
|
this.soundName = soundName;
|
2018-08-16 14:59:39 +08:00
|
|
|
|
this.loop = Loop;
|
2018-06-01 05:38:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Loads the .wav file from disk and plays it.
|
|
|
|
|
/// </summary>
|
|
|
|
|
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);
|
2018-08-16 14:59:39 +08:00
|
|
|
|
count = byteArray.Length;//dynamicSound.GetSampleSizeInBytes(TimeSpan.FromMilliseconds(1000));
|
2018-08-16 04:22:31 +08:00
|
|
|
|
|
|
|
|
|
dynamicSound.BufferNeeded += new EventHandler<EventArgs>(DynamicSound_BufferNeeded);
|
2018-08-17 02:50:50 +08:00
|
|
|
|
|
2018-06-01 05:38:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DynamicSound_BufferNeeded(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
dynamicSound.SubmitBuffer(byteArray, position, count);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception err)
|
|
|
|
|
{
|
2018-08-16 14:59:39 +08:00
|
|
|
|
//SimpleSoundManagerMod.ModMonitor.Log(err.ToString());
|
2018-06-01 05:38:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
position += count;
|
|
|
|
|
if (position + count > byteArray.Length)
|
|
|
|
|
{
|
2018-08-16 14:59:39 +08:00
|
|
|
|
|
|
|
|
|
if (loop)
|
|
|
|
|
{
|
|
|
|
|
position = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
//this.stop();
|
|
|
|
|
}
|
2018-06-01 05:38:24 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Used to pause the current song.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void pause()
|
|
|
|
|
{
|
|
|
|
|
if (dynamicSound != null) dynamicSound.Pause();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Used to play a song.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="name"></param>
|
|
|
|
|
public void play()
|
|
|
|
|
{
|
|
|
|
|
if (this.isPlaying() == true) return;
|
2018-08-16 04:22:31 +08:00
|
|
|
|
LoadWavFromFileToStream();
|
2018-08-17 02:50:50 +08:00
|
|
|
|
dynamicSound.Play();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Used to play a song.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="name"></param>
|
|
|
|
|
/// <param name="volume">How lound the sound is when playing. 0~1.0f</param>
|
|
|
|
|
public void play(float volume)
|
|
|
|
|
{
|
|
|
|
|
if (this.isPlaying() == true) return;
|
|
|
|
|
LoadWavFromFileToStream();
|
|
|
|
|
dynamicSound.Volume = volume;
|
2018-06-01 05:38:24 +08:00
|
|
|
|
dynamicSound.Play();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Used to resume the currently playing song.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void resume()
|
|
|
|
|
{
|
|
|
|
|
if (dynamicSound == null) return;
|
|
|
|
|
dynamicSound.Resume();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Used to stop the currently playing song.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void stop()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (dynamicSound != null)
|
|
|
|
|
{
|
|
|
|
|
dynamicSound.Stop(true);
|
|
|
|
|
dynamicSound.BufferNeeded -= new EventHandler<EventArgs>(DynamicSound_BufferNeeded);
|
|
|
|
|
position = 0;
|
|
|
|
|
count = 0;
|
|
|
|
|
byteArray = new byte[0];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Used to change from one playing song to another;
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="songName"></param>
|
|
|
|
|
public void swap(string pathToNewWavFile)
|
|
|
|
|
{
|
|
|
|
|
this.stop();
|
|
|
|
|
this.path = pathToNewWavFile;
|
|
|
|
|
this.play();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Checks if the song is currently playing.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public bool isPlaying()
|
|
|
|
|
{
|
|
|
|
|
if (this.dynamicSound == null) return false;
|
|
|
|
|
if (this.dynamicSound.State == SoundState.Playing) return true;
|
|
|
|
|
else return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Checks if the song is currently paused.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public bool isPaused()
|
|
|
|
|
{
|
|
|
|
|
if (this.dynamicSound == null) return false;
|
|
|
|
|
if (this.dynamicSound.State == SoundState.Paused) return true;
|
|
|
|
|
else return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Checks if the song is currently stopped.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
public bool isStopped()
|
|
|
|
|
{
|
|
|
|
|
if (this.dynamicSound == null) return false;
|
|
|
|
|
if (this.dynamicSound.State == SoundState.Stopped) return true;
|
|
|
|
|
else return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public Sound clone()
|
|
|
|
|
{
|
2018-08-07 05:01:44 +08:00
|
|
|
|
return new WavSound(this.getSoundName(),this.path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string getSoundName()
|
|
|
|
|
{
|
|
|
|
|
return this.soundName;
|
2018-06-01 05:38:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void restart()
|
|
|
|
|
{
|
|
|
|
|
this.stop();
|
|
|
|
|
this.play();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|