mirror of
https://github.com/9ParsonsB/Pulsar.git
synced 2025-04-05 17:39:39 -04:00
* Add file association for .eop, prompt for install dir * Handle .eop or .aip file passed as arg. * VS2022 version bump * Filter neutron stars and black holes from fast spinning criteria. * Adjustments for new "high value" check * Refactor herald cache * Fix element order and namespaces for voice moods. * Add explicit .Stop() between audio player calls. * Use nullsafe member access instead of skipping * Don't queue up a title that's already queued. * Improve body ordinal handling for explorer speech titles. * Escape strings being inserted into xml * Handle flip-flopping JSON type * Converter for flip-flopping property type * Use the converter * Escape characters *before* we wrap it in xml. * Give Eahlstan his clear button. :D * Exclude all stars from fast rotation check. * Close outstanding popup notifications on exit. * TO DONE * [Herald] Suppress duplicate notification titles for spoken notifications If you have notifications from multiple plugins producing notifications with the same title in quick succession (ie. "Body A 1 e" from both Explorer and BioInsights), the title on successive notifications will not be spoken again to save the breath of our friendly Azure speakers. * Doc update * Remove unintended member hiding * Fix export errors when exporting BioInsights data, cleanup Discovered a couple issues with exporting BioInsights data resulting from using two different types of objects in the data grid; improved error handling as well. Also cleaned up some old-style read all code. * Add read-all on launch setting * Updated framework xml * Improve high-value body description text Co-authored-by: Fred Kuipers <mr.fredk@gmail.com>
142 lines
4.2 KiB
C#
142 lines
4.2 KiB
C#
using NetCoreAudio.Interfaces;
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Timers;
|
|
|
|
namespace NetCoreAudio.Players
|
|
{
|
|
internal class WindowsPlayer : IPlayer
|
|
{
|
|
[DllImport("winmm.dll")]
|
|
private static extern int mciSendString(string command, StringBuilder stringReturn, int returnLength, IntPtr hwndCallback);
|
|
|
|
[DllImport("winmm.dll")]
|
|
private static extern int mciGetErrorString(int errorCode, StringBuilder errorText, int errorTextSize);
|
|
|
|
[DllImport("winmm.dll")]
|
|
public static extern int waveOutSetVolume(IntPtr hwo, uint dwVolume);
|
|
|
|
private Timer _playbackTimer;
|
|
private Stopwatch _playStopwatch;
|
|
|
|
private string _fileName;
|
|
|
|
public event EventHandler PlaybackFinished;
|
|
|
|
public bool Playing { get; private set; }
|
|
public bool Paused { get; private set; }
|
|
|
|
public Task Play(string fileName)
|
|
{
|
|
_fileName = $"\"{fileName}\"";
|
|
_playbackTimer = new Timer
|
|
{
|
|
AutoReset = false
|
|
};
|
|
_playStopwatch = new Stopwatch();
|
|
|
|
ExecuteMciCommand($"Status {_fileName} Length");
|
|
ExecuteMciCommand($"Play {_fileName}");
|
|
Paused = false;
|
|
Playing = true;
|
|
_playbackTimer.Elapsed += HandlePlaybackFinished;
|
|
_playbackTimer.Start();
|
|
_playStopwatch.Start();
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public Task Pause()
|
|
{
|
|
if (Playing && !Paused)
|
|
{
|
|
ExecuteMciCommand($"Pause {_fileName}");
|
|
Paused = true;
|
|
_playbackTimer.Stop();
|
|
_playStopwatch.Stop();
|
|
_playbackTimer.Interval -= _playStopwatch.ElapsedMilliseconds;
|
|
}
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public Task Resume()
|
|
{
|
|
if (Playing && Paused)
|
|
{
|
|
ExecuteMciCommand($"Resume {_fileName}");
|
|
Paused = false;
|
|
_playbackTimer.Start();
|
|
_playStopwatch.Reset();
|
|
_playStopwatch.Start();
|
|
}
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public Task Stop(bool force = false)
|
|
{
|
|
if (Playing || force)
|
|
{
|
|
ExecuteMciCommand($"Stop {_fileName}");
|
|
Playing = false;
|
|
Paused = false;
|
|
_playbackTimer?.Stop();
|
|
_playStopwatch?.Stop();
|
|
}
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private void HandlePlaybackFinished(object sender, ElapsedEventArgs e)
|
|
{
|
|
Playing = false;
|
|
PlaybackFinished?.Invoke(this, e);
|
|
_playbackTimer?.Dispose();
|
|
_playbackTimer = null;
|
|
}
|
|
|
|
private Task ExecuteMciCommand(string commandString)
|
|
{
|
|
var sb = new StringBuilder();
|
|
|
|
var result = mciSendString(commandString, sb, 1024 * 1024, IntPtr.Zero);
|
|
|
|
if (result != 0)
|
|
{
|
|
var errorSb = new StringBuilder($"Error executing MCI command '{commandString}'. Error code: {result}.");
|
|
var sb2 = new StringBuilder(128);
|
|
|
|
mciGetErrorString(result, sb2, 128);
|
|
errorSb.Append($" Message: {sb2}");
|
|
|
|
throw new Exception(errorSb.ToString());
|
|
}
|
|
|
|
if (commandString.ToLower().StartsWith("status") && int.TryParse(sb.ToString(), out var length))
|
|
_playbackTimer.Interval = length + 75;
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public Task SetVolume(byte percent)
|
|
{
|
|
// Calculate the volume that's being set
|
|
int NewVolume = ushort.MaxValue / 100 * percent;
|
|
// Set the same volume for both the left and the right channels
|
|
uint NewVolumeAllChannels = ((uint)NewVolume & 0x0000ffff) | ((uint)NewVolume << 16);
|
|
// Set the volume
|
|
waveOutSetVolume(IntPtr.Zero, NewVolumeAllChannels);
|
|
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Stop().Wait();
|
|
ExecuteMciCommand("Close All");
|
|
}
|
|
}
|
|
}
|