2
0
mirror of https://github.com/9ParsonsB/Pulsar.git synced 2025-04-05 17:39:39 -04:00
Jonathan Miller 8de34a141c
Export version fixes (#83)
* 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>
2022-05-21 13:00:47 -02:30

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");
}
}
}