using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Xna.Framework.Audio;
using SimpleSoundManager.Framework;
using StardewModdingAPI;
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 string path;
public string soundName;
public bool loop;
/// Get a raw disk path to the wav file.
public WavSound(string name, string pathToWavFile, bool loop = false)
{
this.path = pathToWavFile;
this.LoadWavFromFileToStream();
this.soundName = name;
this.loop = loop;
}
/// A constructor that takes a mod helper and a relative path to a wav file.
public WavSound(IModHelper modHelper, string name, string relativePath, bool loop = false)
{
string path = Path.Combine(modHelper.DirectoryPath, relativePath);
this.path = path;
this.soundName = name;
this.loop = loop;
}
/// 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, string soundName, List pathPieces, bool loop = false)
{
string dirPath = modHelper.DirectoryPath;
foreach (string str in pathPieces)
dirPath = Path.Combine(dirPath, str);
this.path = dirPath;
this.soundName = soundName;
this.loop = loop;
}
/// 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;
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();
this.byteArray = reader.ReadBytes(dataSize);
this.dynamicSound = new DynamicSoundEffectInstance(sampleRate, (AudioChannels)channels);
this.count = this.byteArray.Length;//dynamicSound.GetSampleSizeInBytes(TimeSpan.FromMilliseconds(1000));
this.dynamicSound.BufferNeeded += this.DynamicSound_BufferNeeded;
}
void DynamicSound_BufferNeeded(object sender, EventArgs e)
{
try
{
this.dynamicSound.SubmitBuffer(this.byteArray, this.position, this.count);
}
catch { }
this.position += this.count;
if (this.position + this.count > this.byteArray.Length)
{
if (this.loop)
this.position = 0;
//else
// this.stop();
}
}
/// Used to pause the current song.
public void pause()
{
this.dynamicSound?.Pause();
}
/// Used to play a song.
public void play()
{
if (this.isPlaying())
return;
this.LoadWavFromFileToStream();
this.dynamicSound.Play();
}
/// Used to play a song.
/// How lound the sound is when playing. 0~1.0f
public void play(float volume)
{
if (this.isPlaying())
return;
this.LoadWavFromFileToStream();
this.dynamicSound.Volume = volume;
this.dynamicSound.Play();
}
/// Used to resume the currently playing song.
public void resume()
{
this.dynamicSound?.Resume();
}
/// Used to stop the currently playing song.
public void stop()
{
if (this.dynamicSound != null)
{
this.dynamicSound.Stop(true);
this.dynamicSound.BufferNeeded -= this.DynamicSound_BufferNeeded;
this.position = 0;
this.count = 0;
this.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()
{
return this.dynamicSound?.State == SoundState.Playing;
}
/// Checks if the song is currently paused.
public bool isPaused()
{
return this.dynamicSound?.State == SoundState.Paused;
}
/// Checks if the song is currently stopped.
public bool isStopped()
{
return this.dynamicSound?.State == SoundState.Stopped;
}
public Sound clone()
{
return new WavSound(this.getSoundName(), this.path);
}
public string getSoundName()
{
return this.soundName;
}
public void restart()
{
this.stop();
this.play();
}
}
}