2018-06-01 05:38:24 +08:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.IO;
|
2018-12-30 18:00:05 +08:00
|
|
|
using Microsoft.Xna.Framework.Audio;
|
|
|
|
using SimpleSoundManager.Framework;
|
|
|
|
using StardewModdingAPI;
|
2018-06-01 05:38:24 +08:00
|
|
|
|
|
|
|
namespace SimpleSoundManager
|
|
|
|
{
|
|
|
|
class WavSound : Sound
|
|
|
|
{
|
|
|
|
|
2018-12-30 18:00:05 +08:00
|
|
|
/// <summary>Used to actually play the song.</summary>
|
2018-06-01 05:38:24 +08:00
|
|
|
DynamicSoundEffectInstance dynamicSound;
|
2018-12-30 18:00:05 +08:00
|
|
|
|
|
|
|
/// <summary>Used to keep track of where in the song we are.</summary>
|
2018-06-01 05:38:24 +08:00
|
|
|
int position;
|
2018-12-30 18:00:05 +08:00
|
|
|
|
2018-06-01 05:38:24 +08:00
|
|
|
int count;
|
|
|
|
|
2018-12-30 18:00:05 +08:00
|
|
|
/// <summary>Used to store the info for the song.</summary>
|
|
|
|
byte[] byteArray;
|
2018-06-01 05:38:24 +08:00
|
|
|
|
|
|
|
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-12-30 18:00:05 +08:00
|
|
|
/// <summary>Get a raw disk path to the wav file.</summary>
|
|
|
|
public WavSound(string name, string pathToWavFile, bool loop = false)
|
2018-06-01 05:38:24 +08:00
|
|
|
{
|
|
|
|
this.path = pathToWavFile;
|
2018-12-30 18:00:05 +08:00
|
|
|
this.LoadWavFromFileToStream();
|
2018-08-07 05:01:44 +08:00
|
|
|
this.soundName = name;
|
2018-12-30 18:00:05 +08:00
|
|
|
this.loop = loop;
|
2018-06-01 05:38:24 +08:00
|
|
|
}
|
|
|
|
|
2018-12-30 18:00:05 +08:00
|
|
|
/// <summary>A constructor that takes a mod helper and a relative path to a wav file.</summary>
|
2019-01-06 13:31:40 +08:00
|
|
|
public WavSound(IModHelper modHelper, string name, string relativePath, bool loop = false)
|
2018-06-01 05:38:24 +08:00
|
|
|
{
|
2019-01-06 13:31:40 +08:00
|
|
|
string path = Path.Combine(modHelper.DirectoryPath, relativePath);
|
2018-06-01 05:38:24 +08:00
|
|
|
this.path = path;
|
2018-08-07 05:01:44 +08:00
|
|
|
this.soundName = name;
|
2018-12-30 18:00:05 +08:00
|
|
|
this.loop = loop;
|
2018-06-01 05:38:24 +08:00
|
|
|
}
|
|
|
|
|
2018-12-30 18:00:05 +08:00
|
|
|
/// <summary>Constructor that is more flexible than typing an absolute path.</summary>
|
2018-06-01 05:38:24 +08:00
|
|
|
/// <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-12-30 18:00:05 +08:00
|
|
|
public WavSound(IModHelper modHelper, string soundName, List<string> pathPieces, bool loop = false)
|
2018-06-01 05:38:24 +08:00
|
|
|
{
|
2018-12-30 18:00:05 +08:00
|
|
|
string dirPath = modHelper.DirectoryPath;
|
|
|
|
foreach (string str in pathPieces)
|
|
|
|
dirPath = Path.Combine(dirPath, str);
|
|
|
|
this.path = dirPath;
|
2018-08-07 05:01:44 +08:00
|
|
|
this.soundName = soundName;
|
2018-12-30 18:00:05 +08:00
|
|
|
this.loop = loop;
|
2018-06-01 05:38:24 +08:00
|
|
|
}
|
|
|
|
|
2018-12-30 18:00:05 +08:00
|
|
|
/// <summary>Loads the .wav file from disk and plays it.</summary>
|
2018-06-01 05:38:24 +08:00
|
|
|
public void LoadWavFromFileToStream()
|
|
|
|
{
|
|
|
|
// Create a new SpriteBatch, which can be used to draw textures.
|
|
|
|
|
|
|
|
string file = this.path;
|
2018-12-30 18:00:05 +08:00
|
|
|
Stream waveFileStream = File.OpenRead(file); //TitleContainer.OpenStream(file);
|
2018-06-01 05:38:24 +08:00
|
|
|
|
|
|
|
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();
|
|
|
|
|
2018-12-30 18:00:05 +08:00
|
|
|
this.byteArray = reader.ReadBytes(dataSize);
|
2018-06-01 05:38:24 +08:00
|
|
|
|
|
|
|
|
2018-12-30 18:00:05 +08:00
|
|
|
this.dynamicSound = new DynamicSoundEffectInstance(sampleRate, (AudioChannels)channels);
|
|
|
|
this.count = this.byteArray.Length;//dynamicSound.GetSampleSizeInBytes(TimeSpan.FromMilliseconds(1000));
|
2018-08-16 04:22:31 +08:00
|
|
|
|
2018-12-30 18:00:05 +08:00
|
|
|
this.dynamicSound.BufferNeeded += this.DynamicSound_BufferNeeded;
|
2018-06-01 05:38:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void DynamicSound_BufferNeeded(object sender, EventArgs e)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2018-12-30 18:00:05 +08:00
|
|
|
this.dynamicSound.SubmitBuffer(this.byteArray, this.position, this.count);
|
2018-06-01 05:38:24 +08:00
|
|
|
}
|
2018-12-30 18:00:05 +08:00
|
|
|
catch { }
|
2018-06-01 05:38:24 +08:00
|
|
|
|
2018-12-30 18:00:05 +08:00
|
|
|
this.position += this.count;
|
|
|
|
if (this.position + this.count > this.byteArray.Length)
|
2018-06-01 05:38:24 +08:00
|
|
|
{
|
2018-08-16 14:59:39 +08:00
|
|
|
|
2018-12-30 18:00:05 +08:00
|
|
|
if (this.loop)
|
|
|
|
this.position = 0;
|
|
|
|
//else
|
|
|
|
// this.stop();
|
2018-06-01 05:38:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-30 18:00:05 +08:00
|
|
|
/// <summary>Used to pause the current song.</summary>
|
2018-06-01 05:38:24 +08:00
|
|
|
public void pause()
|
|
|
|
{
|
2018-12-30 18:00:05 +08:00
|
|
|
this.dynamicSound?.Pause();
|
2018-06-01 05:38:24 +08:00
|
|
|
}
|
|
|
|
|
2018-12-30 18:00:05 +08:00
|
|
|
/// <summary>Used to play a song.</summary>
|
2018-06-01 05:38:24 +08:00
|
|
|
public void play()
|
|
|
|
{
|
2018-12-30 18:00:05 +08:00
|
|
|
if (this.isPlaying())
|
|
|
|
return;
|
|
|
|
|
|
|
|
this.LoadWavFromFileToStream();
|
|
|
|
this.dynamicSound.Play();
|
2018-08-17 02:50:50 +08:00
|
|
|
}
|
|
|
|
|
2018-12-30 18:00:05 +08:00
|
|
|
/// <summary>Used to play a song.</summary>
|
2018-08-17 02:50:50 +08:00
|
|
|
/// <param name="volume">How lound the sound is when playing. 0~1.0f</param>
|
|
|
|
public void play(float volume)
|
|
|
|
{
|
2018-12-30 18:00:05 +08:00
|
|
|
if (this.isPlaying())
|
|
|
|
return;
|
|
|
|
|
|
|
|
this.LoadWavFromFileToStream();
|
|
|
|
this.dynamicSound.Volume = volume;
|
|
|
|
this.dynamicSound.Play();
|
2018-06-01 05:38:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-12-30 18:00:05 +08:00
|
|
|
/// <summary>Used to resume the currently playing song.</summary>
|
2018-06-01 05:38:24 +08:00
|
|
|
public void resume()
|
|
|
|
{
|
2018-12-30 18:00:05 +08:00
|
|
|
dynamicSound?.Resume();
|
2018-06-01 05:38:24 +08:00
|
|
|
}
|
|
|
|
|
2018-12-30 18:00:05 +08:00
|
|
|
/// <summary>Used to stop the currently playing song.</summary>
|
2018-06-01 05:38:24 +08:00
|
|
|
public void stop()
|
|
|
|
{
|
2018-12-30 18:00:05 +08:00
|
|
|
if (this.dynamicSound != null)
|
2018-06-01 05:38:24 +08:00
|
|
|
{
|
2018-12-30 18:00:05 +08:00
|
|
|
this.dynamicSound.Stop(true);
|
|
|
|
this.dynamicSound.BufferNeeded -= this.DynamicSound_BufferNeeded;
|
|
|
|
this.position = 0;
|
|
|
|
this.count = 0;
|
|
|
|
this.byteArray = new byte[0];
|
2018-06-01 05:38:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-30 18:00:05 +08:00
|
|
|
/// <summary>Used to change from one playing song to another;</summary>
|
2018-06-01 05:38:24 +08:00
|
|
|
public void swap(string pathToNewWavFile)
|
|
|
|
{
|
|
|
|
this.stop();
|
|
|
|
this.path = pathToNewWavFile;
|
|
|
|
this.play();
|
|
|
|
}
|
|
|
|
|
2018-12-30 18:00:05 +08:00
|
|
|
/// <summary>Checks if the song is currently playing.</summary>
|
2018-06-01 05:38:24 +08:00
|
|
|
public bool isPlaying()
|
|
|
|
{
|
2018-12-30 18:00:05 +08:00
|
|
|
return this.dynamicSound?.State == SoundState.Playing;
|
2018-06-01 05:38:24 +08:00
|
|
|
}
|
|
|
|
|
2018-12-30 18:00:05 +08:00
|
|
|
/// <summary>Checks if the song is currently paused.</summary>
|
2018-06-01 05:38:24 +08:00
|
|
|
public bool isPaused()
|
|
|
|
{
|
2018-12-30 18:00:05 +08:00
|
|
|
return this.dynamicSound?.State == SoundState.Paused;
|
2018-06-01 05:38:24 +08:00
|
|
|
}
|
|
|
|
|
2018-12-30 18:00:05 +08:00
|
|
|
/// <summary>Checks if the song is currently stopped.</summary>
|
2018-06-01 05:38:24 +08:00
|
|
|
public bool isStopped()
|
|
|
|
{
|
2018-12-30 18:00:05 +08:00
|
|
|
return this.dynamicSound?.State == SoundState.Stopped;
|
2018-06-01 05:38:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public Sound clone()
|
|
|
|
{
|
2018-12-30 18:00:05 +08:00
|
|
|
return new WavSound(this.getSoundName(), this.path);
|
2018-08-07 05:01:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public string getSoundName()
|
|
|
|
{
|
|
|
|
return this.soundName;
|
2018-06-01 05:38:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public void restart()
|
|
|
|
{
|
|
|
|
this.stop();
|
|
|
|
this.play();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|