diff --git a/audio-service/metadata.json b/audio-service/metadata.json index ab0150f..6d6381d 100644 --- a/audio-service/metadata.json +++ b/audio-service/metadata.json @@ -22,11 +22,11 @@ "volume": 0.25 }, { - "endTime": 27.516843118383072, + "endTime": 28.566433566433446, "filename": "C:\\Users\\mickl\\Desktop\\cliptrim-ui\\ClipTrimApp\\audio-service\\recordings\\audio_capture_20260220_200442.wav", "name": "Clip 20260220_200442", "playbackType": "playOverlap", - "startTime": 25.120307988450435, + "startTime": 25.664335664335663, "volume": 0.64 } ] diff --git a/audio-service/requirements.txt b/audio-service/requirements.txt index 1387b40..e77454c 100644 --- a/audio-service/requirements.txt +++ b/audio-service/requirements.txt @@ -1,7 +1,6 @@ -sounddevice==0.5.1 -numpy==1.22.3 -python-osc==1.9.3 -scipy==1.10.1 -comtypes==1.4.8 -pycaw==20240210 -Flask==3.1.2 \ No newline at end of file +Flask==3.1.3 +flask_cors==6.0.2 +flask_socketio==5.6.1 +numpy==2.4.2 +scipy==1.17.1 +sounddevice==0.5.5 diff --git a/audio-service/src/__pycache__/metadata_manager.cpython-313.pyc b/audio-service/src/__pycache__/metadata_manager.cpython-313.pyc index 010768b..e5f17ec 100644 Binary files a/audio-service/src/__pycache__/metadata_manager.cpython-313.pyc and b/audio-service/src/__pycache__/metadata_manager.cpython-313.pyc differ diff --git a/audio-service/src/__pycache__/windows_audio.cpython-313.pyc b/audio-service/src/__pycache__/windows_audio.cpython-313.pyc index 2dd30a5..10c03f7 100644 Binary files a/audio-service/src/__pycache__/windows_audio.cpython-313.pyc and b/audio-service/src/__pycache__/windows_audio.cpython-313.pyc differ diff --git a/audio-service/src/main.py b/audio-service/src/main.py index b9ec183..a1aab8c 100644 --- a/audio-service/src/main.py +++ b/audio-service/src/main.py @@ -19,7 +19,7 @@ import threading app = Flask(__name__) CORS(app) -socketio = SocketIO(app, cors_allowed_origins="*") +socketio = SocketIO(app, cors_allowed_origins="*", logger=True, engineio_logger=True, async_mode='eventlet') @socketio.on('connect') def handle_connect(): @@ -31,6 +31,14 @@ def record_clip(data): io = AudioIO() io.save_last_n_seconds(); +@socketio.on('play_clip') +def play_clip(data): + io = AudioIO() + print(f"Received play_clip event with data: {data}") + if data: + io.play_clip(data) + + def main(): # Create argument parser parser = argparse.ArgumentParser(description='Audio Recording Service') @@ -65,8 +73,9 @@ def main(): app.register_blueprint(device_bp) app.register_blueprint(metadata_bp) app.register_blueprint(settings_bp) + print(f"Starting Flask server on port {settings.get_settings('http_port')}") # app.run(host='127.0.0.1', port=settings.get_settings('http_port'), debug=False, use_reloader=True) - socketio.run(app, host='127.0.0.1', port=settings.get_settings('http_port'), debug=False, use_reloader=True) + socketio.run(app, host='127.0.0.1', port=settings.get_settings('http_port'), debug=False, use_reloader=True, allow_unsafe_werkzeug=True) diff --git a/audio-service/src/routes/__pycache__/settings.cpython-313.pyc b/audio-service/src/routes/__pycache__/settings.cpython-313.pyc index 5dd959a..d859b80 100644 Binary files a/audio-service/src/routes/__pycache__/settings.cpython-313.pyc and b/audio-service/src/routes/__pycache__/settings.cpython-313.pyc differ diff --git a/audio-service/src/windows_audio.py b/audio-service/src/windows_audio.py index 55dd493..38f2468 100644 --- a/audio-service/src/windows_audio.py +++ b/audio-service/src/windows_audio.py @@ -1,9 +1,5 @@ import sounddevice as sd import numpy as np -import comtypes -import comtypes.client -from comtypes import CLSCTX_ALL -from pycaw.pycaw import AudioUtilities, IAudioEndpointVolume import json class WindowsAudioManager: diff --git a/electron-ui/src/main/main.ts b/electron-ui/src/main/main.ts index caf9382..743fc30 100644 --- a/electron-ui/src/main/main.ts +++ b/electron-ui/src/main/main.ts @@ -112,9 +112,6 @@ const createWindow = async () => { registerFileIpcHandlers(); - const pythonManager = new PythonSubprocessManager('src/main.py'); - - pythonManager.start(); // Remove this if your app does not use auto updates // eslint-disable-next-line new AppUpdater(); @@ -135,6 +132,8 @@ app.on('window-all-closed', () => { app .whenReady() .then(() => { + const pythonManager = new PythonSubprocessManager('src/main.py'); + pythonManager.start(); createWindow(); app.on('activate', () => { // On macOS it's common to re-create a window in the app when the diff --git a/electron-ui/src/main/service.ts b/electron-ui/src/main/service.ts index e79633c..7759355 100644 --- a/electron-ui/src/main/service.ts +++ b/electron-ui/src/main/service.ts @@ -40,10 +40,10 @@ export default class PythonSubprocessManager { }, ); this.process.stdout.on('data', (data: Buffer) => { - console.log(`Python stdout: ${data.toString()}`); + // console.log(`Python stdout: ${data.toString()}`); }); this.process.stderr.on('data', (data: Buffer) => { - // console.error(`Python stderr: ${data.toString()}`); + // console.error(`Python stderr: ${data.toString()}`); const lines = data.toString().split('\n'); // eslint-disable-next-line no-restricted-syntax for (const line of lines) { diff --git a/stream_deck_plugin/ClipTrimDotNet/Client/ClipTrimClient.cs b/stream_deck_plugin/ClipTrimDotNet/Client/ClipTrimClient.cs index f3f3c24..83df12e 100644 --- a/stream_deck_plugin/ClipTrimDotNet/Client/ClipTrimClient.cs +++ b/stream_deck_plugin/ClipTrimDotNet/Client/ClipTrimClient.cs @@ -1,13 +1,14 @@ -using System; +using BarRaider.SdTools; +using Newtonsoft.Json; +using SocketIOClient; +using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; +using System.Runtime.CompilerServices; using System.Text; using System.Threading.Tasks; -using Newtonsoft.Json; -using SocketIOClient; -using BarRaider.SdTools; -using System.Runtime.CompilerServices; +using static System.Runtime.InteropServices.JavaScript.JSType; namespace ClipTrimDotNet.Client { @@ -78,44 +79,32 @@ namespace ClipTrimDotNet.Client return Task.CompletedTask; }); - Task.Run(async () => await socket.ConnectAsync()); - //Task.Run(ShortPoll); + socket.OnDisconnected += (sender, e) => + { + Logger.Instance.LogMessage(TracingLevel.INFO, $"Socket disconnected: {e}"); + Task.Run(async () => await Connect()); + }; + Task.Run(async () => await Connect()); } + public async Task Connect() + { + while (!socket.Connected) + { + try + { + await socket.ConnectAsync(); + } + catch + { - //public async Task ShortPoll() - //{ - // while (true) - // { - // await GetMetadata(); - // await Task.Delay(TimeSpan.FromSeconds(5)); await Task.Delay(TimeSpan.FromSeconds(5)); - - // } - //} + } + } + } public List Collections { get; private set; } = new List(); public int SelectedCollection { get; private set; } = -1; public int PageIndex { get; private set; } = 0; - //private async Task GetMetadata() - //{ - // try - // { - // var response = await httpClient.GetAsync("meta"); - // if (response.IsSuccessStatusCode) - // { - // var json = await response.Content.ReadAsStringAsync(); - // dynamic collections = JsonConvert.DeserializeObject(json); - // collections = collections.collections; - // Collections = JsonConvert.DeserializeObject>(collections.ToString()); - // } - // } - // catch (Exception ex) - // { - // //Logger.Instance.LogMessage(TracingLevel.INFO, $"Error pinging ClipTrim API: {ex.Message}"); - // return; - // } - - //} public List GetCollectionNames() { @@ -134,6 +123,7 @@ namespace ClipTrimDotNet.Client public ClipMetadata? GetClipByPagedIndex(int index) { + SelectedCollection = Collections.FindIndex(x => x.Name == GlobalSettings.Instance.ProfileName); if (SelectedCollection == -1) return null; int clipIndex = PageIndex * 10 + index; var collection = Collections[SelectedCollection]; @@ -147,12 +137,8 @@ namespace ClipTrimDotNet.Client public async void PlayClip(ClipMetadata? metadata) { if (metadata == null) return; - - //var response = await httpClient.PostAsync("playback/start", new StringContent(JsonConvert.SerializeObject(metadata), Encoding.UTF8, "application/json")); - //if (!response.IsSuccessStatusCode) - //{ - // //Logger.Instance.LogMessage(TracingLevel.INFO, $"Error playing clip: {response.ReasonPhrase}"); - //} + Logger.Instance.LogMessage(TracingLevel.INFO, $"playing clip:"); + await socket.EmitAsync("play_clip", new List() { metadata }); } } } diff --git a/stream_deck_plugin/ClipTrimDotNet/GlobalSettings.cs b/stream_deck_plugin/ClipTrimDotNet/GlobalSettings.cs index e0e2643..02618d9 100644 --- a/stream_deck_plugin/ClipTrimDotNet/GlobalSettings.cs +++ b/stream_deck_plugin/ClipTrimDotNet/GlobalSettings.cs @@ -10,28 +10,6 @@ using Newtonsoft.Json.Linq; namespace ClipTrimDotNet { - public class FileEntry - { - public FileEntry() - { - Volume = 1.0; - Playtype = "Play/Overlap"; - } - [JsonProperty(PropertyName = "Volume")] - public double Volume { get; set; } - [JsonProperty(PropertyName = "Playtype")] - public string Playtype { get; set; } - } - public class CollectionEntry - { - public CollectionEntry() - { - Files = new Dictionary(); - } - [JsonProperty(PropertyName = "Files")] - public Dictionary Files { get; set; } - } - public class GlobalSettings { public static GlobalSettings? _inst; @@ -50,59 +28,18 @@ namespace ClipTrimDotNet public static GlobalSettings CreateDefaultSettings() { GlobalSettings instance = new GlobalSettings(); - instance.BasePath = null; instance.ProfileName = null; - instance.Collections = new Dictionary(); return instance; } - [FilenameProperty] - [JsonProperty(PropertyName = "basePath")] - public string? BasePath { get; set; } - [JsonProperty(PropertyName = "profileName")] public string? ProfileName { get; set; } - [JsonProperty(PropertyName = "outputDevice")] - public string? OutputDevice { get; set; } - - [JsonProperty(PropertyName = "collections")] - public Dictionary Collections { get; set; } public void SetCurrentProfile(string profile) { ProfileName = profile; - if(!Collections.ContainsKey(profile)) - { - Collections.Add(profile, new CollectionEntry()); - } - } - - public FileEntry GetFileOptionsInCurrentProfile(string filename) - { - if(!Collections.TryGetValue(ProfileName, out CollectionEntry collection)) - { - return new FileEntry(); - } - if(!collection.Files.TryGetValue(filename, out FileEntry file)) - { - return new FileEntry(); - } - //Logger.Instance.LogMessage(TracingLevel.INFO, "fetched file settings " + filename + JsonConvert.SerializeObject(file)); - return file; - } - - public void SetFileOptionsCurrentProfile(string filename, FileEntry file) - { - //Logger.Instance.LogMessage(TracingLevel.INFO, "SetFileOptionsCurrentProfile "); - if (!Collections.TryGetValue(ProfileName, out CollectionEntry collection)) - { - return; - } - //Logger.Instance.LogMessage(TracingLevel.INFO, "SetFileOptionsCurrentProfile 2"); - //collection.Files[filename] = file; - Collections[ProfileName].Files[filename] = file; } } } diff --git a/stream_deck_plugin/ClipTrimDotNet/Player.cs b/stream_deck_plugin/ClipTrimDotNet/Player.cs index e7343db..d3b3cb7 100644 --- a/stream_deck_plugin/ClipTrimDotNet/Player.cs +++ b/stream_deck_plugin/ClipTrimDotNet/Player.cs @@ -20,53 +20,15 @@ namespace ClipTrimDotNet private ClipMetadata? metadata; private KeyCoordinates coordinates; - private class PluginSettings - { - public static PluginSettings CreateDefaultSettings() - { - PluginSettings instance = new PluginSettings(); - instance.Path = null; - instance.PlayType = "Play/Overlap"; - instance.Index = 0; - instance.Volume = 1; - return instance; - } - [FilenameProperty] - [JsonPropertyName("path")] - public string? Path { get; set; } - - [JsonPropertyName("index")] - public int? Index { get; set; } - [JsonPropertyName("playtype")] - public string PlayType { get; set; } - - [JsonPropertyName("volume")] - public double Volume { get; set; } - } - - #region Private Members - - private PluginSettings settings; - - #endregion public Player(SDConnection connection, InitialPayload payload) : base(connection, payload) { - if (payload.Settings == null || payload.Settings.Count == 0) - { - this.settings = PluginSettings.CreateDefaultSettings(); - SaveSettings(); - } - else - { - this.settings = payload.Settings.ToObject(); - } this.coordinates = payload.Coordinates; GlobalSettingsManager.Instance.RequestGlobalSettings(); CheckFile(); } - private void Instance_OnReceivedGlobalSettings(object sender, ReceivedGlobalSettingsPayload e) + public void Instance_OnReceivedGlobalSettings(object sender, ReceivedGlobalSettingsPayload e) { Tools.AutoPopulateSettings(GlobalSettings.Instance, e.Settings); } @@ -78,77 +40,17 @@ namespace ClipTrimDotNet private async void CheckFile() { - - //if (settings == null || GlobalSettings.Instance.ProfileName ==null) return; metadata = ClipTrimClient.Instance.GetClipByPagedIndex(GetIndex()); await Connection.SetTitleAsync($"{metadata?.Name ?? ""}"); - //Logger.Instance.LogMessage(TracingLevel.INFO, $"Set title to {metadata?.Name ?? ""}"); - - return; - - //var files = Directory.GetFiles(Path.Combine(Path.GetDirectoryName(GlobalSettings.Instance.BasePath), GlobalSettings.Instance.ProfileName), "*.wav", SearchOption.TopDirectoryOnly) - // .OrderBy(file => File.GetCreationTime(file)) - // .ToArray(); - //int? i = this.settings.Index; - //string new_path = ""; - //if (i != null && i >= 0 && i < files.Length) - //{ - // new_path = files[i ?? 0]; - //} - - - //await Connection.SetTitleAsync(Path.GetFileNameWithoutExtension(new_path)); - //if (new_path != settings.Path) - //{ - // settings.Path = new_path; - // if(new_path != "") - // { - // FileEntry opts = GlobalSettings.Instance.GetFileOptionsInCurrentProfile(new_path); - // settings.Volume = opts.Volume; - // settings.PlayType = opts.Playtype; - // } - // await SaveSettings(); - //} - } - - - private async void Connection_OnApplicationDidLaunch(object sender, BarRaider.SdTools.Wrappers.SDEventReceivedEventArgs e) - { - - } - - private void Connection_OnTitleParametersDidChange(object sender, SDEventReceivedEventArgs e) - { - //titleParameters = e.Event?.Payload?.TitleParameters; - //userTitle = e.Event?.Payload?.Title; } public override void Dispose() { - Connection.OnTitleParametersDidChange -= Connection_OnTitleParametersDidChange; - Connection.OnApplicationDidLaunch -= Connection_OnApplicationDidLaunch; - //Logger.Instance.LogMessage(TracingLevel.INFO, $"Destructor called"); } public override void KeyPressed(KeyPayload payload) { - //Logger.Instance.LogMessage(TracingLevel.INFO, "Key Pressedd"); - Tools.AutoPopulateSettings(settings, payload.Settings); - // Logger.Instance.LogMessage(TracingLevel.INFO, JsonConvert.SerializeObject(settings)); ClipTrimClient.Instance.PlayClip(metadata); - //try - //{ - // WavPlayer.Instance.Play(settings.Path, GlobalSettings.Instance.OutputDevice, settings.Volume, settings.PlayType == "Play/Overlap" ? WavPlayer.PlayMode.PlayOverlap : WavPlayer.PlayMode.PlayStop); - //} - //catch - //{ - - //} - - } - - public override void KeyReleased(KeyPayload payload) { - } @@ -156,19 +58,8 @@ namespace ClipTrimDotNet CheckFile(); } - public override async void ReceivedSettings(ReceivedSettingsPayload payload) - { - //Logger.Instance.LogMessage(TracingLevel.INFO, "Player rec settings"); - Tools.AutoPopulateSettings(settings, payload.Settings); - GlobalSettings.Instance.SetFileOptionsCurrentProfile(settings.Path, new FileEntry() { Playtype = settings.PlayType, Volume = settings.Volume }); - await Connection.SetGlobalSettingsAsync(JObject.FromObject(GlobalSettings.Instance)); - //SaveSettings(); - //CheckFile(); - } public override void ReceivedGlobalSettings(ReceivedGlobalSettingsPayload payload) { - //Logger.Instance.LogMessage(TracingLevel.INFO, "ReceivedGlobalSettings"); - if (payload.Settings == null || payload.Settings.Count == 0) { var inst = GlobalSettings.Instance; @@ -178,17 +69,17 @@ namespace ClipTrimDotNet { GlobalSettings.Instance = payload.Settings.ToObject(); } - - //CheckFile(); } - #region Private Methods - - private Task SaveSettings() + public override void KeyReleased(KeyPayload payload) { - return Connection.SetSettingsAsync(JObject.FromObject(settings)); + + } + + public override void ReceivedSettings(ReceivedSettingsPayload payload) + { + } - #endregion } } \ No newline at end of file diff --git a/stream_deck_plugin/ClipTrimDotNet/ProfileSwitcher.cs b/stream_deck_plugin/ClipTrimDotNet/ProfileSwitcher.cs index aa29bbd..d95eed0 100644 --- a/stream_deck_plugin/ClipTrimDotNet/ProfileSwitcher.cs +++ b/stream_deck_plugin/ClipTrimDotNet/ProfileSwitcher.cs @@ -49,7 +49,7 @@ namespace ClipTrimDotNet } else { - this.settings = payload.Settings.ToObject(); + this.settings = payload.Settings.ToObject()!; } GlobalSettingsManager.Instance.RequestGlobalSettings(); Connection.OnSendToPlugin += Connection_OnSendToPlugin; @@ -62,57 +62,33 @@ namespace ClipTrimDotNet await Connection.SetTitleAsync(settings.ProfileName + " B"); } - private async void Connection_OnSendToPlugin(object sender, SDEventReceivedEventArgs e) + private async void Connection_OnSendToPlugin(object? sender, SDEventReceivedEventArgs e) { //Logger.Instance.LogMessage(TracingLevel.INFO, "get profiles"); - if (e.Event.Payload["event"].ToString() == "getProfiles") + if (e.Event.Payload["event"] is null) return; + + if (e.Event.Payload["event"]!.ToString() == "getProfiles") { - //string basePath = "C:\\Users\\mickl\\Music\\clips"; - //var files = Directory.GetDirectories(basePath, "*", SearchOption.TopDirectoryOnly).Select(x => Path.GetFileNameWithoutExtension(x)).Where(x => x != "original"); var files = ClipTrimClient.Instance.GetCollectionNames(); var items = files.Select(x => new DataSourceItem { label = x, value = x}); - var obj = new JObject(); - obj["event"] = "getProfiles"; - obj["items"] = JArray.FromObject(items); - //Logger.Instance.LogMessage(TracingLevel.INFO, "get profiles return " + JsonConvert.SerializeObject(obj)); + var obj = new JObject + { + ["event"] = "getProfiles", + ["items"] = JArray.FromObject(items) + }; await Connection.SendToPropertyInspectorAsync(obj); } - //if (e.Event.Payload["event"].ToString() == "getOutputDevices") - //{ - // List devices = new List(); - // for (int n = -1; n < WaveOut.DeviceCount; n++) - // { - // var caps = WaveOut.GetCapabilities(n); - // devices.Add(caps); - // } - // var items = devices.Select(x => new DataSourceItem { label = x.ProductName, value = x.ProductName }); - // var obj = new JObject(); - // obj["event"] = "getOutputDevices"; - // obj["items"] = JArray.FromObject(items); - // //Logger.Instance.LogMessage(TracingLevel.INFO, "get devices return " + JsonConvert.SerializeObject(obj)); - // await Connection.SendToPropertyInspectorAsync(obj); - //} } - private void Connection_OnTitleParametersDidChange(object sender, SDEventReceivedEventArgs e) - { - } public override void Dispose() { - Connection.OnTitleParametersDidChange -= Connection_OnTitleParametersDidChange; - //Logger.Instance.LogMessage(TracingLevel.INFO, $"Destructor called"); } public override async void KeyPressed(KeyPayload payload) { - //Logger.Instance.LogMessage(TracingLevel.INFO, "KeyPressed"); - //Logger.Instance.LogMessage(TracingLevel.INFO, JsonConvert.SerializeObject(settings)); - //Logger.Instance.LogMessage(TracingLevel.INFO, JsonConvert.SerializeObject(GlobalSettings.Instance)); - ClipTrimClient.Instance.SetSelectedCollectionByName(settings.ProfileName); - GlobalSettings.Instance.SetCurrentProfile(settings.ProfileName); - //Logger.Instance.LogMessage(TracingLevel.INFO, JsonConvert.SerializeObject(GlobalSettings.Instance)); + GlobalSettings.Instance.SetCurrentProfile(settings.ProfileName??""); await Connection.SetGlobalSettingsAsync(JObject.FromObject(GlobalSettings.Instance)); await Connection.SwitchProfileAsync("ClipTrim"); @@ -132,25 +108,18 @@ namespace ClipTrimDotNet { Tools.AutoPopulateSettings(settings, payload.Settings); SaveSettings(); - //tTitle(); - //CheckFile(); } public override void ReceivedGlobalSettings(ReceivedGlobalSettingsPayload payload) { - //Logger.Instance.LogMessage(TracingLevel.INFO, "ReceivedGlobalSettings"); - if (payload.Settings == null || payload.Settings.Count == 0) { var inst = GlobalSettings.Instance; - //GlobalSettingsManager.Instance.SetGlobalSettings(JObject.FromObject(inst)); } else { GlobalSettings.Instance = payload.Settings.ToObject(); } - - //CheckFile(); } #region Private Methods diff --git a/stream_deck_plugin/ClipTrimDotNet/PropertyInspector/file_player.html b/stream_deck_plugin/ClipTrimDotNet/PropertyInspector/file_player.html index 21a7ef5..c088656 100644 --- a/stream_deck_plugin/ClipTrimDotNet/PropertyInspector/file_player.html +++ b/stream_deck_plugin/ClipTrimDotNet/PropertyInspector/file_player.html @@ -11,7 +11,7 @@ - + \ No newline at end of file diff --git a/stream_deck_plugin/ClipTrimDotNet/PropertyInspector/profile_swticher.html b/stream_deck_plugin/ClipTrimDotNet/PropertyInspector/profile_swticher.html index 49498c2..ec89269 100644 --- a/stream_deck_plugin/ClipTrimDotNet/PropertyInspector/profile_swticher.html +++ b/stream_deck_plugin/ClipTrimDotNet/PropertyInspector/profile_swticher.html @@ -16,7 +16,7 @@ show-refresh="true" placeholder="Select a ClipTrim page"> - + diff --git a/stream_deck_plugin/ClipTrimDotNet/WavPlayer.cs b/stream_deck_plugin/ClipTrimDotNet/WavPlayer.cs deleted file mode 100644 index 04867ee..0000000 --- a/stream_deck_plugin/ClipTrimDotNet/WavPlayer.cs +++ /dev/null @@ -1,225 +0,0 @@ -//using System; -//using System.Collections.Concurrent; -//using System.Collections.Generic; -//using System.Linq; -//using System.ServiceModel.Security; -//using System.Threading.Tasks; -//using BarRaider.SdTools; -//using NAudio.Wave; -//using NAudio.Wave.SampleProviders; -//using Newtonsoft.Json; - -//class CachedSound -//{ -// public byte[] AudioData { get; private set; } -// public WaveFormat WaveFormat { get; private set; } -// public CachedSound(string audioFileName) -// { -// using (var audioFileReader = new AudioFileReader(audioFileName)) -// { -// // TODO: could add resampling in here if required -// WaveFormat = audioFileReader.WaveFormat; -// var wholeFile = new List((int)(audioFileReader.Length)); -// var readBuffer = new byte[audioFileReader.WaveFormat.SampleRate * audioFileReader.WaveFormat.Channels*4]; -// int samplesRead; -// while ((samplesRead = audioFileReader.Read(readBuffer, 0, readBuffer.Length)) > 0) -// { -// wholeFile.AddRange(readBuffer.Take(samplesRead)); -// } -// AudioData = wholeFile.ToArray(); -// } -// //Logger.Instance.LogMessage(TracingLevel.INFO, $"AudioData Length {AudioData.Length}"); - -// } -//} -//class CachedSoundSampleProvider : IWaveProvider -//{ -// private readonly CachedSound cachedSound; -// private long position; - -// ~CachedSoundSampleProvider() { -// //Logger.Instance.LogMessage(TracingLevel.INFO, $"Cache destructor"); -// } - -// public CachedSoundSampleProvider(CachedSound cachedSound) -// { -// this.cachedSound = cachedSound; -// position = 0; -// } - -// public int Read(byte[] buffer, int offset, int count) -// { -// //Logger.Instance.LogMessage(TracingLevel.INFO, $"Read1 byte"); -// var availableSamples = cachedSound.AudioData.Length - position; -// var samplesToCopy = Math.Min(availableSamples, count); -// try -// { -// //Logger.Instance.LogMessage(TracingLevel.INFO, $"{cachedSound.AudioData.GetType()} {buffer.GetType()}"); -// Array.Copy(cachedSound.AudioData, position, buffer, offset, samplesToCopy); -// } -// catch (Exception ex) -// { -// //Logger.Instance.LogMessage(TracingLevel.INFO, $"{ex.ToString()}"); -// } -// //Logger.Instance.LogMessage(TracingLevel.INFO, $"Read3"); -// position += samplesToCopy; -// //Logger.Instance.LogMessage(TracingLevel.INFO, $"Sending {samplesToCopy} samples"); -// return (int)samplesToCopy; -// } - -// public WaveFormat WaveFormat => cachedSound.WaveFormat; -//} - -//public class WavPlayer -//{ -// private static WavPlayer? instance; -// public static WavPlayer Instance -// { -// get -// { -// instance ??= new WavPlayer(); -// return instance; -// } - -// } -// public enum PlayMode -// { -// PlayOverlap, -// PlayStop -// } - -// private readonly ConcurrentDictionary>> _activePlayers; - -// public WavPlayer() -// { -// _activePlayers = new ConcurrentDictionary>>(); -// } - -// public void Play(string filePath, string id, double volume, PlayMode mode) -// { -// if (string.IsNullOrWhiteSpace(filePath)) -// throw new ArgumentException("File path cannot be null or empty.", nameof(filePath)); - -// if (mode == PlayMode.PlayOverlap) -// { -// PlayWithOverlap(filePath, id, volume); -// } -// else if (mode == PlayMode.PlayStop) -// { -// PlayWithStop(filePath, id, volume); -// } -// else -// { -// throw new ArgumentOutOfRangeException(nameof(mode), "Invalid play mode specified."); -// } -// } - -// private void PlayWithOverlap(string filePath, string id, double volume) -// { - -// try -// { -// //Logger.Instance.LogMessage(TracingLevel.INFO, "Play overlap"); -// var player = CreatePlayer(filePath, id); - -// if (!_activePlayers.ContainsKey(filePath)) -// { -// _activePlayers[filePath] = new List>(); -// } - -// _activePlayers[filePath].Add(player); -// player.Item1.Volume = (float)volume; -// player.Item1.Play(); -// } -// catch(Exception ex) -// { -// //Logger.Instance.LogMessage(TracingLevel.INFO, ex.ToString()); -// } - -// //var playersToDispose = _activePlayers[filePath].Where(x => x.Item1.PlaybackState == PlaybackState.Stopped).ToList(); -// //foreach (var p in playersToDispose) -// //{ -// // p.Item1.Stop(); -// // p.Item1.Dispose(); -// //} -// //_activePlayers[filePath].RemoveAll(x => x.Item1.PlaybackState == PlaybackState.Stopped); -// } - -// private void PlayWithStop(string filePath, string id, double volume) -// { -// if (_activePlayers.TryGetValue(filePath, out var players)) -// { - -// // Stop and dispose all current players for this file -// if (players.Any(x => x.Item1.PlaybackState == PlaybackState.Playing)) -// { -// var playersToDispose = players.ToList(); -// foreach (var player in playersToDispose) -// { -// player.Item1.Stop(); -// player.Item1.Dispose(); -// } -// } -// else -// { -// PlayWithOverlap(filePath, id, volume); -// } - -// } -// else -// { -// // Start a new player -// PlayWithOverlap(filePath, id, volume); -// } - -// _activePlayers[filePath].RemoveAll(x => x.Item1.PlaybackState == PlaybackState.Stopped); -// } - -// private Tuple CreatePlayer(string filePath, string name) -// { -// var reader = new CachedSoundSampleProvider(new CachedSound(filePath)); -// //var reader = new AudioFileReader(filePath); -// int number = -1; -// for (int i = 0; i < WaveOut.DeviceCount; ++i) -// { -// if (WaveOut.GetCapabilities(i).ProductName == name) -// { -// number = i; -// } -// } -// var player = new WaveOutEvent() { DeviceNumber = number }; -// player.Init(reader); -// return new Tuple(player, reader); -// } - -// private void CleanupPlayer(string filePath) -// { -// if (_activePlayers.TryGetValue(filePath, out var players)) -// { -// var playersToDispose = players.ToList(); -// foreach (var p in playersToDispose) -// { -// p.Item1.Stop(); -// p.Item1.Dispose(); -// } -// } -// _activePlayers[filePath].RemoveAll(x => x.Item1.PlaybackState == PlaybackState.Stopped); - -// } - -// public void StopAll() -// { -// foreach (var players in _activePlayers.Values) -// { -// var playersToDispose = players.ToList(); -// foreach (var player in playersToDispose) -// { -// player.Item1.Stop(); -// player.Item1.Dispose(); -// } -// players.Clear(); -// } - -// _activePlayers.Clear(); -// } -//}