socket set up properly

This commit is contained in:
michalcourson
2026-02-26 15:48:41 -05:00
parent e7f649ae0b
commit bc40f9abe3
14 changed files with 267 additions and 261 deletions

View File

@ -95,7 +95,7 @@ class MetaDataManager:
collection["clips"] = new_order collection["clips"] = new_order
if not self.socket is None: if not self.socket is None:
self.socket.emit('collection_updated', {'collection': collection}) self.socket.emit('collection_updated', collection)
self.save_metadata() self.save_metadata()
def save_metadata(self): def save_metadata(self):

View File

@ -28,4 +28,5 @@ def set_all_settings():
SettingsManager().set_settings(name, value) SettingsManager().set_settings(name, value)
return jsonify({'status': 'success', 'settings': settings}) return jsonify({'status': 'success', 'settings': settings})
except ValueError as e: except ValueError as e:
return jsonify({'status': 'error', 'message': str(e)}), 400 return jsonify({'status': 'error', 'message': str(e)}), 400

View File

@ -5,8 +5,6 @@ VisualStudioVersion = 17.8.34330.188
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClipTrimDotNet", "ClipTrimDotNet\ClipTrimDotNet.csproj", "{4635D874-69C0-4010-BE46-77EF92EB1553}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClipTrimDotNet", "ClipTrimDotNet\ClipTrimDotNet.csproj", "{4635D874-69C0-4010-BE46-77EF92EB1553}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClientTest", "ClientTest\ClientTest.csproj", "{245B4C42-D83B-4381-8B79-ECC11238CD88}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -17,10 +15,6 @@ Global
{4635D874-69C0-4010-BE46-77EF92EB1553}.Debug|Any CPU.Build.0 = Debug|Any CPU {4635D874-69C0-4010-BE46-77EF92EB1553}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4635D874-69C0-4010-BE46-77EF92EB1553}.Release|Any CPU.ActiveCfg = Release|Any CPU {4635D874-69C0-4010-BE46-77EF92EB1553}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4635D874-69C0-4010-BE46-77EF92EB1553}.Release|Any CPU.Build.0 = Release|Any CPU {4635D874-69C0-4010-BE46-77EF92EB1553}.Release|Any CPU.Build.0 = Release|Any CPU
{245B4C42-D83B-4381-8B79-ECC11238CD88}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{245B4C42-D83B-4381-8B79-ECC11238CD88}.Debug|Any CPU.Build.0 = Debug|Any CPU
{245B4C42-D83B-4381-8B79-ECC11238CD88}.Release|Any CPU.ActiveCfg = Release|Any CPU
{245B4C42-D83B-4381-8B79-ECC11238CD88}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Text.Json.Serialization;
namespace ClipTrimDotNet.Client namespace ClipTrimDotNet.Client
{ {
@ -18,27 +19,35 @@ namespace ClipTrimDotNet.Client
public class ClipMetadata public class ClipMetadata
{ {
[JsonProperty(PropertyName = "filename")] [JsonProperty(PropertyName = "filename")]
[JsonPropertyName("filename")]
public string Filename { get; set; } public string Filename { get; set; }
[JsonProperty(PropertyName = "name")] [JsonProperty(PropertyName = "name")]
[JsonPropertyName("name")]
public string Name { get; set; } public string Name { get; set; }
[JsonProperty(PropertyName = "volume")] [JsonProperty(PropertyName = "volume")]
[JsonPropertyName("volume")]
public double Volume { get; set; } = 1.0; public double Volume { get; set; } = 1.0;
[JsonProperty(PropertyName = "startTime")] [JsonProperty(PropertyName = "startTime")]
[JsonPropertyName("startTime")]
public double StartTime { get; set; } = 0.0; public double StartTime { get; set; } = 0.0;
[JsonProperty(PropertyName = "endTime")] [JsonProperty(PropertyName = "endTime")]
[JsonPropertyName("endTime")]
public double EndTime { get; set; } = 0.0; public double EndTime { get; set; } = 0.0;
[JsonProperty(PropertyName = "playbackType")] [JsonProperty(PropertyName = "playbackType")]
[JsonConverter(typeof(StringEnumConverter))] [Newtonsoft.Json.JsonConverter(typeof(StringEnumConverter))]
[System.Text.Json.Serialization.JsonConverter(typeof(JsonStringEnumConverter))]
[JsonPropertyName("playbackType")]
public PlaybackType PlaybackType { get; set; } = PlaybackType.playStop; public PlaybackType PlaybackType { get; set; } = PlaybackType.playStop;
} }
} }

View File

@ -38,6 +38,7 @@ namespace ClipTrimDotNet.Client
// BaseAddress = new Uri("http://localhost:5010/"), // BaseAddress = new Uri("http://localhost:5010/"),
// Timeout = TimeSpan.FromSeconds(10) // Timeout = TimeSpan.FromSeconds(10)
//}; //};
Logger.Instance.LogMessage(TracingLevel.INFO, $"Starting ClipTrimClient on port {PortNumber}");
socket = new SocketIO(new Uri($"http://localhost:5010/")); socket = new SocketIO(new Uri($"http://localhost:5010/"));
socket.Options.AutoUpgrade = false; socket.Options.AutoUpgrade = false;
socket.Options.ConnectionTimeout = TimeSpan.FromSeconds(10); socket.Options.ConnectionTimeout = TimeSpan.FromSeconds(10);
@ -46,11 +47,14 @@ namespace ClipTrimDotNet.Client
{ {
try try
{ {
Collections = JsonConvert.DeserializeObject<List<CollectionMetaData>>(ctx.RawText); var response = ctx.GetValue<List<CollectionMetaData>>(0);
Logger.Instance.LogMessage(TracingLevel.INFO, $"full_data event {JsonConvert.SerializeObject(response)}");
Collections = response!;
//Logger.Instance.LogMessage(TracingLevel.INFO, $"Collections {JsonConvert.SerializeObject(Collections)}");
} }
catch catch (Exception ex)
{ {
Logger.Instance.LogMessage(TracingLevel.INFO, $"full_data error {ex.ToString()}");
} }
return Task.CompletedTask; return Task.CompletedTask;
}); });
@ -58,18 +62,19 @@ namespace ClipTrimDotNet.Client
{ {
try try
{ {
var collection = JsonConvert.DeserializeObject<CollectionMetaData>(ctx.RawText); var response = ctx.GetValue<CollectionMetaData>(0)!;
int index = Collections.FindIndex(x => x.Id == collection.Id); Logger.Instance.LogMessage(TracingLevel.INFO, $"collection_updated event {JsonConvert.SerializeObject(response)}");
if(index != -1) int index = Collections.FindIndex(x => x.Id == response.Id);
if (index != -1)
{ {
Collections[index] = collection; Collections[index] = response;
} }
} }
catch catch
{ {
} }
return Task.CompletedTask; return Task.CompletedTask;
}); });
@ -89,7 +94,7 @@ namespace ClipTrimDotNet.Client
//} //}
public List<CollectionMetaData> Collections { get; private set; } = new List<CollectionMetaData>(); public List<CollectionMetaData> Collections { get; private set; } = new List<CollectionMetaData>();
public CollectionMetaData? SelectedCollection { get; private set; } public int SelectedCollection { get; private set; } = -1;
public int PageIndex { get; private set; } = 0; public int PageIndex { get; private set; } = 0;
//private async Task GetMetadata() //private async Task GetMetadata()
//{ //{
@ -120,21 +125,21 @@ namespace ClipTrimDotNet.Client
public void SetSelectedCollectionByName(string name) public void SetSelectedCollectionByName(string name)
{ {
var collection = Collections.FirstOrDefault(x => x.Name == name); SelectedCollection = Collections.FindIndex(x => x.Name == name);
if (collection != null) if (SelectedCollection != -1)
{ {
SelectedCollection = collection;
PageIndex = 0; PageIndex = 0;
} }
} }
public ClipMetadata? GetClipByPagedIndex(int index) public ClipMetadata? GetClipByPagedIndex(int index)
{ {
if (SelectedCollection == null) return null; if (SelectedCollection == -1) return null;
int clipIndex = PageIndex * 10 + index; int clipIndex = PageIndex * 10 + index;
if (clipIndex >= 0 && clipIndex < SelectedCollection.Clips.Count) var collection = Collections[SelectedCollection];
if (clipIndex >= 0 && clipIndex < collection.Clips.Count)
{ {
return SelectedCollection.Clips[clipIndex]; return collection.Clips[clipIndex];
} }
return null; return null;
} }

View File

@ -3,6 +3,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace ClipTrimDotNet.Client namespace ClipTrimDotNet.Client
@ -10,14 +11,17 @@ namespace ClipTrimDotNet.Client
public class CollectionMetaData public class CollectionMetaData
{ {
[JsonProperty(PropertyName = "name")] [JsonProperty(PropertyName = "name")]
[JsonPropertyName("name")]
public string Name { get; set; } public string Name { get; set; }
[JsonProperty(PropertyName = "clips")] [JsonProperty(PropertyName = "clips")]
[JsonPropertyName("clips")]
public List<ClipMetadata> Clips { get; set; } = new List<ClipMetadata>(); public List<ClipMetadata> Clips { get; set; } = new List<ClipMetadata>();
[JsonProperty(PropertyName = "id")] [JsonProperty(PropertyName = "id")]
[JsonPropertyName("id")]
public int Id { get; set; } public int Id { get; set; }
} }
} }

View File

@ -1,8 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net8.0-windows</TargetFramework>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<LangVersion>8</LangVersion> <LangVersion>10</LangVersion>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<PreBuildEvent>npm run stop</PreBuildEvent> <PreBuildEvent>npm run stop</PreBuildEvent>
@ -28,13 +29,6 @@
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.2" /> <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.2" />
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.2" /> <PackageReference Include="Microsoft.Extensions.Options" Version="10.0.2" />
<PackageReference Include="Microsoft.Extensions.Primitives" Version="10.0.2" /> <PackageReference Include="Microsoft.Extensions.Primitives" Version="10.0.2" />
<PackageReference Include="NAudio" Version="2.2.1" />
<PackageReference Include="NAudio.Asio" Version="2.2.1" />
<PackageReference Include="NAudio.Core" Version="2.2.1" />
<PackageReference Include="NAudio.Midi" Version="2.2.1" />
<PackageReference Include="NAudio.Wasapi" Version="2.2.1" />
<PackageReference Include="NAudio.WinForms" Version="2.2.1" />
<PackageReference Include="NAudio.WinMM" Version="2.2.1" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
<PackageReference Include="NLog" Version="6.0.5" /> <PackageReference Include="NLog" Version="6.0.5" />
<PackageReference Include="SocketIOClient" Version="4.0.0.2" /> <PackageReference Include="SocketIOClient" Version="4.0.0.2" />

View File

@ -7,7 +7,6 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using BarRaider.SdTools.Wrappers; using BarRaider.SdTools.Wrappers;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using NAudio.MediaFoundation;
namespace ClipTrimDotNet namespace ClipTrimDotNet
{ {
@ -90,18 +89,18 @@ namespace ClipTrimDotNet
{ {
return new FileEntry(); return new FileEntry();
} }
Logger.Instance.LogMessage(TracingLevel.INFO, "fetched file settings " + filename + JsonConvert.SerializeObject(file)); //Logger.Instance.LogMessage(TracingLevel.INFO, "fetched file settings " + filename + JsonConvert.SerializeObject(file));
return file; return file;
} }
public void SetFileOptionsCurrentProfile(string filename, FileEntry file) public void SetFileOptionsCurrentProfile(string filename, FileEntry file)
{ {
Logger.Instance.LogMessage(TracingLevel.INFO, "SetFileOptionsCurrentProfile "); //Logger.Instance.LogMessage(TracingLevel.INFO, "SetFileOptionsCurrentProfile ");
if (!Collections.TryGetValue(ProfileName, out CollectionEntry collection)) if (!Collections.TryGetValue(ProfileName, out CollectionEntry collection))
{ {
return; return;
} }
Logger.Instance.LogMessage(TracingLevel.INFO, "SetFileOptionsCurrentProfile 2"); //Logger.Instance.LogMessage(TracingLevel.INFO, "SetFileOptionsCurrentProfile 2");
//collection.Files[filename] = file; //collection.Files[filename] = file;
Collections[ProfileName].Files[filename] = file; Collections[ProfileName].Files[filename] = file;
} }

View File

@ -1,7 +1,6 @@
using BarRaider.SdTools; using BarRaider.SdTools;
using BarRaider.SdTools.Wrappers; using BarRaider.SdTools.Wrappers;
using ClipTrimDotNet.Client; using ClipTrimDotNet.Client;
using NAudio.CoreAudioApi.Interfaces;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System; using System;
@ -83,7 +82,8 @@ namespace ClipTrimDotNet
//if (settings == null || GlobalSettings.Instance.ProfileName ==null) return; //if (settings == null || GlobalSettings.Instance.ProfileName ==null) return;
metadata = ClipTrimClient.Instance.GetClipByPagedIndex(GetIndex()); metadata = ClipTrimClient.Instance.GetClipByPagedIndex(GetIndex());
await Connection.SetTitleAsync($"{metadata?.Name ?? ""}"); await Connection.SetTitleAsync($"{metadata?.Name ?? ""}");
//Logger.Instance.LogMessage(TracingLevel.INFO, $"Set title to {metadata?.Name ?? ""}");
return; return;
//var files = Directory.GetFiles(Path.Combine(Path.GetDirectoryName(GlobalSettings.Instance.BasePath), GlobalSettings.Instance.ProfileName), "*.wav", SearchOption.TopDirectoryOnly) //var files = Directory.GetFiles(Path.Combine(Path.GetDirectoryName(GlobalSettings.Instance.BasePath), GlobalSettings.Instance.ProfileName), "*.wav", SearchOption.TopDirectoryOnly)
@ -151,13 +151,14 @@ namespace ClipTrimDotNet
} }
public override void OnTick() { public override void OnTick() {
CheckFile(); CheckFile();
} }
public override async void ReceivedSettings(ReceivedSettingsPayload payload) public override async void ReceivedSettings(ReceivedSettingsPayload payload)
{ {
Logger.Instance.LogMessage(TracingLevel.INFO, "Player rec settings"); //Logger.Instance.LogMessage(TracingLevel.INFO, "Player rec settings");
Tools.AutoPopulateSettings(settings, payload.Settings); Tools.AutoPopulateSettings(settings, payload.Settings);
GlobalSettings.Instance.SetFileOptionsCurrentProfile(settings.Path, new FileEntry() { Playtype = settings.PlayType, Volume = settings.Volume }); GlobalSettings.Instance.SetFileOptionsCurrentProfile(settings.Path, new FileEntry() { Playtype = settings.PlayType, Volume = settings.Volume });
await Connection.SetGlobalSettingsAsync(JObject.FromObject(GlobalSettings.Instance)); await Connection.SetGlobalSettingsAsync(JObject.FromObject(GlobalSettings.Instance));

View File

@ -1,8 +1,6 @@
using BarRaider.SdTools; using BarRaider.SdTools;
using BarRaider.SdTools.Wrappers; using BarRaider.SdTools.Wrappers;
using ClipTrimDotNet.Client; using ClipTrimDotNet.Client;
using NAudio.CoreAudioApi.Interfaces;
using NAudio.Wave;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using System; using System;
@ -61,7 +59,7 @@ namespace ClipTrimDotNet
private async void SetTitle() private async void SetTitle()
{ {
await Connection.SetTitleAsync(settings.ProfileName + " A"); await Connection.SetTitleAsync(settings.ProfileName + " B");
} }
private async void Connection_OnSendToPlugin(object sender, SDEventReceivedEventArgs<BarRaider.SdTools.Events.SendToPlugin> e) private async void Connection_OnSendToPlugin(object sender, SDEventReceivedEventArgs<BarRaider.SdTools.Events.SendToPlugin> e)
@ -79,21 +77,21 @@ namespace ClipTrimDotNet
//Logger.Instance.LogMessage(TracingLevel.INFO, "get profiles return " + JsonConvert.SerializeObject(obj)); //Logger.Instance.LogMessage(TracingLevel.INFO, "get profiles return " + JsonConvert.SerializeObject(obj));
await Connection.SendToPropertyInspectorAsync(obj); await Connection.SendToPropertyInspectorAsync(obj);
} }
if (e.Event.Payload["event"].ToString() == "getOutputDevices") //if (e.Event.Payload["event"].ToString() == "getOutputDevices")
{ //{
List<WaveOutCapabilities> devices = new List<WaveOutCapabilities>(); // List<WaveOutCapabilities> devices = new List<WaveOutCapabilities>();
for (int n = -1; n < WaveOut.DeviceCount; n++) // for (int n = -1; n < WaveOut.DeviceCount; n++)
{ // {
var caps = WaveOut.GetCapabilities(n); // var caps = WaveOut.GetCapabilities(n);
devices.Add(caps); // devices.Add(caps);
} // }
var items = devices.Select(x => new DataSourceItem { label = x.ProductName, value = x.ProductName }); // var items = devices.Select(x => new DataSourceItem { label = x.ProductName, value = x.ProductName });
var obj = new JObject(); // var obj = new JObject();
obj["event"] = "getOutputDevices"; // obj["event"] = "getOutputDevices";
obj["items"] = JArray.FromObject(items); // obj["items"] = JArray.FromObject(items);
//Logger.Instance.LogMessage(TracingLevel.INFO, "get devices return " + JsonConvert.SerializeObject(obj)); // //Logger.Instance.LogMessage(TracingLevel.INFO, "get devices return " + JsonConvert.SerializeObject(obj));
await Connection.SendToPropertyInspectorAsync(obj); // await Connection.SendToPropertyInspectorAsync(obj);
} //}
} }
@ -114,7 +112,7 @@ namespace ClipTrimDotNet
//Logger.Instance.LogMessage(TracingLevel.INFO, JsonConvert.SerializeObject(GlobalSettings.Instance)); //Logger.Instance.LogMessage(TracingLevel.INFO, JsonConvert.SerializeObject(GlobalSettings.Instance));
ClipTrimClient.Instance.SetSelectedCollectionByName(settings.ProfileName); ClipTrimClient.Instance.SetSelectedCollectionByName(settings.ProfileName);
GlobalSettings.Instance.SetCurrentProfile(settings.ProfileName); GlobalSettings.Instance.SetCurrentProfile(settings.ProfileName);
Logger.Instance.LogMessage(TracingLevel.INFO, JsonConvert.SerializeObject(GlobalSettings.Instance)); //Logger.Instance.LogMessage(TracingLevel.INFO, JsonConvert.SerializeObject(GlobalSettings.Instance));
await Connection.SetGlobalSettingsAsync(JObject.FromObject(GlobalSettings.Instance)); await Connection.SetGlobalSettingsAsync(JObject.FromObject(GlobalSettings.Instance));
await Connection.SwitchProfileAsync("ClipTrim"); await Connection.SwitchProfileAsync("ClipTrim");

View File

@ -13,6 +13,7 @@ namespace ClipTrimDotNet
{ {
// Uncomment this line of code to allow for debugging // Uncomment this line of code to allow for debugging
//while (!System.Diagnostics.Debugger.IsAttached) { System.Threading.Thread.Sleep(100); } //while (!System.Diagnostics.Debugger.IsAttached) { System.Threading.Thread.Sleep(100); }
Client.ClipTrimClient.Instance.PortNumber = 5010;
SDWrapper.Run(args); SDWrapper.Run(args);
} }
} }

View File

@ -1,225 +1,225 @@
using System; //using System;
using System.Collections.Concurrent; //using System.Collections.Concurrent;
using System.Collections.Generic; //using System.Collections.Generic;
using System.Linq; //using System.Linq;
using System.ServiceModel.Security; //using System.ServiceModel.Security;
using System.Threading.Tasks; //using System.Threading.Tasks;
using BarRaider.SdTools; //using BarRaider.SdTools;
using NAudio.Wave; //using NAudio.Wave;
using NAudio.Wave.SampleProviders; //using NAudio.Wave.SampleProviders;
using Newtonsoft.Json; //using Newtonsoft.Json;
class CachedSound //class CachedSound
{ //{
public byte[] AudioData { get; private set; } // public byte[] AudioData { get; private set; }
public WaveFormat WaveFormat { get; private set; } // public WaveFormat WaveFormat { get; private set; }
public CachedSound(string audioFileName) // public CachedSound(string audioFileName)
{ // {
using (var audioFileReader = new AudioFileReader(audioFileName)) // using (var audioFileReader = new AudioFileReader(audioFileName))
{ // {
// TODO: could add resampling in here if required // // TODO: could add resampling in here if required
WaveFormat = audioFileReader.WaveFormat; // WaveFormat = audioFileReader.WaveFormat;
var wholeFile = new List<byte>((int)(audioFileReader.Length)); // var wholeFile = new List<byte>((int)(audioFileReader.Length));
var readBuffer = new byte[audioFileReader.WaveFormat.SampleRate * audioFileReader.WaveFormat.Channels*4]; // var readBuffer = new byte[audioFileReader.WaveFormat.SampleRate * audioFileReader.WaveFormat.Channels*4];
int samplesRead; // int samplesRead;
while ((samplesRead = audioFileReader.Read(readBuffer, 0, readBuffer.Length)) > 0) // while ((samplesRead = audioFileReader.Read(readBuffer, 0, readBuffer.Length)) > 0)
{ // {
wholeFile.AddRange(readBuffer.Take(samplesRead)); // wholeFile.AddRange(readBuffer.Take(samplesRead));
} // }
AudioData = wholeFile.ToArray(); // AudioData = wholeFile.ToArray();
} // }
//Logger.Instance.LogMessage(TracingLevel.INFO, $"AudioData Length {AudioData.Length}"); // //Logger.Instance.LogMessage(TracingLevel.INFO, $"AudioData Length {AudioData.Length}");
} // }
} //}
class CachedSoundSampleProvider : IWaveProvider //class CachedSoundSampleProvider : IWaveProvider
{ //{
private readonly CachedSound cachedSound; // private readonly CachedSound cachedSound;
private long position; // private long position;
~CachedSoundSampleProvider() { // ~CachedSoundSampleProvider() {
//Logger.Instance.LogMessage(TracingLevel.INFO, $"Cache destructor"); // //Logger.Instance.LogMessage(TracingLevel.INFO, $"Cache destructor");
} // }
public CachedSoundSampleProvider(CachedSound cachedSound) // public CachedSoundSampleProvider(CachedSound cachedSound)
{ // {
this.cachedSound = cachedSound; // this.cachedSound = cachedSound;
position = 0; // position = 0;
} // }
public int Read(byte[] buffer, int offset, int count) // public int Read(byte[] buffer, int offset, int count)
{ // {
//Logger.Instance.LogMessage(TracingLevel.INFO, $"Read1 byte"); // //Logger.Instance.LogMessage(TracingLevel.INFO, $"Read1 byte");
var availableSamples = cachedSound.AudioData.Length - position; // var availableSamples = cachedSound.AudioData.Length - position;
var samplesToCopy = Math.Min(availableSamples, count); // var samplesToCopy = Math.Min(availableSamples, count);
try // try
{ // {
//Logger.Instance.LogMessage(TracingLevel.INFO, $"{cachedSound.AudioData.GetType()} {buffer.GetType()}"); // //Logger.Instance.LogMessage(TracingLevel.INFO, $"{cachedSound.AudioData.GetType()} {buffer.GetType()}");
Array.Copy(cachedSound.AudioData, position, buffer, offset, samplesToCopy); // Array.Copy(cachedSound.AudioData, position, buffer, offset, samplesToCopy);
} // }
catch (Exception ex) // catch (Exception ex)
{ // {
//Logger.Instance.LogMessage(TracingLevel.INFO, $"{ex.ToString()}"); // //Logger.Instance.LogMessage(TracingLevel.INFO, $"{ex.ToString()}");
} // }
//Logger.Instance.LogMessage(TracingLevel.INFO, $"Read3"); // //Logger.Instance.LogMessage(TracingLevel.INFO, $"Read3");
position += samplesToCopy; // position += samplesToCopy;
//Logger.Instance.LogMessage(TracingLevel.INFO, $"Sending {samplesToCopy} samples"); // //Logger.Instance.LogMessage(TracingLevel.INFO, $"Sending {samplesToCopy} samples");
return (int)samplesToCopy; // return (int)samplesToCopy;
} // }
public WaveFormat WaveFormat => cachedSound.WaveFormat; // public WaveFormat WaveFormat => cachedSound.WaveFormat;
} //}
public class WavPlayer //public class WavPlayer
{ //{
private static WavPlayer? instance; // private static WavPlayer? instance;
public static WavPlayer Instance // public static WavPlayer Instance
{ // {
get // get
{ // {
instance ??= new WavPlayer(); // instance ??= new WavPlayer();
return instance; // return instance;
} // }
} // }
public enum PlayMode // public enum PlayMode
{ // {
PlayOverlap, // PlayOverlap,
PlayStop // PlayStop
} // }
private readonly ConcurrentDictionary<string, List<Tuple<WaveOutEvent, IWaveProvider>>> _activePlayers; // private readonly ConcurrentDictionary<string, List<Tuple<WaveOutEvent, IWaveProvider>>> _activePlayers;
public WavPlayer() // public WavPlayer()
{ // {
_activePlayers = new ConcurrentDictionary<string, List<Tuple<WaveOutEvent, IWaveProvider>>>(); // _activePlayers = new ConcurrentDictionary<string, List<Tuple<WaveOutEvent, IWaveProvider>>>();
} // }
public void Play(string filePath, string id, double volume, PlayMode mode) // public void Play(string filePath, string id, double volume, PlayMode mode)
{ // {
if (string.IsNullOrWhiteSpace(filePath)) // if (string.IsNullOrWhiteSpace(filePath))
throw new ArgumentException("File path cannot be null or empty.", nameof(filePath)); // throw new ArgumentException("File path cannot be null or empty.", nameof(filePath));
if (mode == PlayMode.PlayOverlap) // if (mode == PlayMode.PlayOverlap)
{ // {
PlayWithOverlap(filePath, id, volume); // PlayWithOverlap(filePath, id, volume);
} // }
else if (mode == PlayMode.PlayStop) // else if (mode == PlayMode.PlayStop)
{ // {
PlayWithStop(filePath, id, volume); // PlayWithStop(filePath, id, volume);
} // }
else // else
{ // {
throw new ArgumentOutOfRangeException(nameof(mode), "Invalid play mode specified."); // throw new ArgumentOutOfRangeException(nameof(mode), "Invalid play mode specified.");
} // }
} // }
private void PlayWithOverlap(string filePath, string id, double volume) // private void PlayWithOverlap(string filePath, string id, double volume)
{ // {
try // try
{ // {
//Logger.Instance.LogMessage(TracingLevel.INFO, "Play overlap"); // //Logger.Instance.LogMessage(TracingLevel.INFO, "Play overlap");
var player = CreatePlayer(filePath, id); // var player = CreatePlayer(filePath, id);
if (!_activePlayers.ContainsKey(filePath)) // if (!_activePlayers.ContainsKey(filePath))
{ // {
_activePlayers[filePath] = new List<Tuple<WaveOutEvent, IWaveProvider>>(); // _activePlayers[filePath] = new List<Tuple<WaveOutEvent, IWaveProvider>>();
} // }
_activePlayers[filePath].Add(player); // _activePlayers[filePath].Add(player);
player.Item1.Volume = (float)volume; // player.Item1.Volume = (float)volume;
player.Item1.Play(); // player.Item1.Play();
} // }
catch(Exception ex) // catch(Exception ex)
{ // {
//Logger.Instance.LogMessage(TracingLevel.INFO, ex.ToString()); // //Logger.Instance.LogMessage(TracingLevel.INFO, ex.ToString());
} // }
//var playersToDispose = _activePlayers[filePath].Where(x => x.Item1.PlaybackState == PlaybackState.Stopped).ToList(); // //var playersToDispose = _activePlayers[filePath].Where(x => x.Item1.PlaybackState == PlaybackState.Stopped).ToList();
//foreach (var p in playersToDispose) // //foreach (var p in playersToDispose)
//{ // //{
// p.Item1.Stop(); // // p.Item1.Stop();
// p.Item1.Dispose(); // // p.Item1.Dispose();
//} // //}
//_activePlayers[filePath].RemoveAll(x => x.Item1.PlaybackState == PlaybackState.Stopped); // //_activePlayers[filePath].RemoveAll(x => x.Item1.PlaybackState == PlaybackState.Stopped);
} // }
private void PlayWithStop(string filePath, string id, double volume) // private void PlayWithStop(string filePath, string id, double volume)
{ // {
if (_activePlayers.TryGetValue(filePath, out var players)) // if (_activePlayers.TryGetValue(filePath, out var players))
{ // {
// Stop and dispose all current players for this file // // Stop and dispose all current players for this file
if (players.Any(x => x.Item1.PlaybackState == PlaybackState.Playing)) // if (players.Any(x => x.Item1.PlaybackState == PlaybackState.Playing))
{ // {
var playersToDispose = players.ToList(); // var playersToDispose = players.ToList();
foreach (var player in playersToDispose) // foreach (var player in playersToDispose)
{ // {
player.Item1.Stop(); // player.Item1.Stop();
player.Item1.Dispose(); // player.Item1.Dispose();
} // }
} // }
else // else
{ // {
PlayWithOverlap(filePath, id, volume); // PlayWithOverlap(filePath, id, volume);
} // }
} // }
else // else
{ // {
// Start a new player // // Start a new player
PlayWithOverlap(filePath, id, volume); // PlayWithOverlap(filePath, id, volume);
} // }
_activePlayers[filePath].RemoveAll(x => x.Item1.PlaybackState == PlaybackState.Stopped); // _activePlayers[filePath].RemoveAll(x => x.Item1.PlaybackState == PlaybackState.Stopped);
} // }
private Tuple<WaveOutEvent, IWaveProvider> CreatePlayer(string filePath, string name) // private Tuple<WaveOutEvent, IWaveProvider> CreatePlayer(string filePath, string name)
{ // {
var reader = new CachedSoundSampleProvider(new CachedSound(filePath)); // var reader = new CachedSoundSampleProvider(new CachedSound(filePath));
//var reader = new AudioFileReader(filePath); // //var reader = new AudioFileReader(filePath);
int number = -1; // int number = -1;
for (int i = 0; i < WaveOut.DeviceCount; ++i) // for (int i = 0; i < WaveOut.DeviceCount; ++i)
{ // {
if (WaveOut.GetCapabilities(i).ProductName == name) // if (WaveOut.GetCapabilities(i).ProductName == name)
{ // {
number = i; // number = i;
} // }
} // }
var player = new WaveOutEvent() { DeviceNumber = number }; // var player = new WaveOutEvent() { DeviceNumber = number };
player.Init(reader); // player.Init(reader);
return new Tuple<WaveOutEvent, IWaveProvider>(player, reader); // return new Tuple<WaveOutEvent, IWaveProvider>(player, reader);
} // }
private void CleanupPlayer(string filePath) // private void CleanupPlayer(string filePath)
{ // {
if (_activePlayers.TryGetValue(filePath, out var players)) // if (_activePlayers.TryGetValue(filePath, out var players))
{ // {
var playersToDispose = players.ToList(); // var playersToDispose = players.ToList();
foreach (var p in playersToDispose) // foreach (var p in playersToDispose)
{ // {
p.Item1.Stop(); // p.Item1.Stop();
p.Item1.Dispose(); // p.Item1.Dispose();
} // }
} // }
_activePlayers[filePath].RemoveAll(x => x.Item1.PlaybackState == PlaybackState.Stopped); // _activePlayers[filePath].RemoveAll(x => x.Item1.PlaybackState == PlaybackState.Stopped);
} // }
public void StopAll() // public void StopAll()
{ // {
foreach (var players in _activePlayers.Values) // foreach (var players in _activePlayers.Values)
{ // {
var playersToDispose = players.ToList(); // var playersToDispose = players.ToList();
foreach (var player in playersToDispose) // foreach (var player in playersToDispose)
{ // {
player.Item1.Stop(); // player.Item1.Stop();
player.Item1.Dispose(); // player.Item1.Dispose();
} // }
players.Clear(); // players.Clear();
} // }
_activePlayers.Clear(); // _activePlayers.Clear();
} // }
} //}

View File

@ -1,12 +1,12 @@
{ {
"scripts": { "scripts": {
"stop": "streamdeck stop com.michal-courson.cliptrim", "stop": "streamdeck stop com.michal-courson.cliptrim",
"copy": "@powershell robocopy bin/Debug/ClipTrimDotNet.sdPlugin bin/Debug/com.michal-courson.cliptrim.sdPlugin", "copy": "@powershell robocopy bin/Debug/ClipTrimDotNet.sdPlugin bin/Debug/com.michal-courson.cliptrim.sdPlugin/net8.0-windows",
"link": "streamdeck link bin/Debug/com.michal-courson.cliptrim.sdPlugin", "link": "streamdeck link bin/Debug/com.michal-courson.cliptrim.sdPlugin",
"restart": "streamdeck restart com.michal-courson.cliptrim", "restart": "streamdeck restart com.michal-courson.cliptrim",
"start": "npm run link && npm run restart", "start": "npm run link && npm run restart",
"all": "npm run stop && npm run copy && npm run link && npm run restart", "all": "npm run stop && npm run copy && npm run link && npm run restart",
"pack": "streamdeck pack bin/Debug/com.michal-courson.cliptrim.sdPlugin/" "pack": "streamdeck pack bin/Debug/com.michal-courson.cliptrim.sdPlugin/net8.0-windows/"
}, },
"devDependencies": { "devDependencies": {
"shx": "^0.3.4" "shx": "^0.3.4"