diff --git a/src/Console/RodelAudio.Console/RodelAudio.Console.csproj b/src/Console/RodelAudio.Console/RodelAudio.Console.csproj index 810c97ea..e6938505 100644 --- a/src/Console/RodelAudio.Console/RodelAudio.Console.csproj +++ b/src/Console/RodelAudio.Console/RodelAudio.Console.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net9.0 enable enable diff --git a/src/Console/RodelChat.Console/RodelChat.Console.csproj b/src/Console/RodelChat.Console/RodelChat.Console.csproj index aa42976c..d5d3abfb 100644 --- a/src/Console/RodelChat.Console/RodelChat.Console.csproj +++ b/src/Console/RodelChat.Console/RodelChat.Console.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net9.0 enable enable diff --git a/src/Console/RodelDraw.Console/RodelDraw.Console.csproj b/src/Console/RodelDraw.Console/RodelDraw.Console.csproj index 4c61c468..eecf15eb 100644 --- a/src/Console/RodelDraw.Console/RodelDraw.Console.csproj +++ b/src/Console/RodelDraw.Console/RodelDraw.Console.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net9.0 enable enable diff --git a/src/Console/RodelTranslate.Console/RodelTranslate.Console.csproj b/src/Console/RodelTranslate.Console/RodelTranslate.Console.csproj index 2e2b0bbe..5a07a228 100644 --- a/src/Console/RodelTranslate.Console/RodelTranslate.Console.csproj +++ b/src/Console/RodelTranslate.Console/RodelTranslate.Console.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net9.0 enable enable diff --git a/src/Core/RodelAgent.Context/RodelAgent.Context.csproj b/src/Core/RodelAgent.Context/RodelAgent.Context.csproj index 8d7fb7bd..1f25125d 100644 --- a/src/Core/RodelAgent.Context/RodelAgent.Context.csproj +++ b/src/Core/RodelAgent.Context/RodelAgent.Context.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable diff --git a/src/Core/RodelAudio.Core/RodelAudio.Core.csproj b/src/Core/RodelAudio.Core/RodelAudio.Core.csproj index c5d50290..354927f1 100644 --- a/src/Core/RodelAudio.Core/RodelAudio.Core.csproj +++ b/src/Core/RodelAudio.Core/RodelAudio.Core.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable diff --git a/src/Core/RodelChat.Core/RodelChat.Core.csproj b/src/Core/RodelChat.Core/RodelChat.Core.csproj index 085337a1..a80c2240 100644 --- a/src/Core/RodelChat.Core/RodelChat.Core.csproj +++ b/src/Core/RodelChat.Core/RodelChat.Core.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable $(NoWarn);SKEXP0110 diff --git a/src/Core/RodelDraw.Core/RodelDraw.Core.csproj b/src/Core/RodelDraw.Core/RodelDraw.Core.csproj index d758bc46..c996ab1c 100644 --- a/src/Core/RodelDraw.Core/RodelDraw.Core.csproj +++ b/src/Core/RodelDraw.Core/RodelDraw.Core.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable diff --git a/src/Core/RodelTranslate.Core/RodelTranslate.Core.csproj b/src/Core/RodelTranslate.Core/RodelTranslate.Core.csproj index f10cf88f..51d187ea 100644 --- a/src/Core/RodelTranslate.Core/RodelTranslate.Core.csproj +++ b/src/Core/RodelTranslate.Core/RodelTranslate.Core.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable diff --git a/src/Desktop/RodelAgent.UI/Controls/Audio/AudioSessionItemControl.xaml.cs b/src/Desktop/RodelAgent.UI/Controls/Audio/AudioSessionItemControl.xaml.cs index 76b851f8..95de833d 100644 --- a/src/Desktop/RodelAgent.UI/Controls/Audio/AudioSessionItemControl.xaml.cs +++ b/src/Desktop/RodelAgent.UI/Controls/Audio/AudioSessionItemControl.xaml.cs @@ -42,7 +42,7 @@ private void Initialize() } private void OnSessionClick(object sender, RoutedEventArgs e) - => GetSessionViewModel().LoadSessionCommand.Execute(ViewModel); + => GetSessionViewModel().LoadSessionCommand.Execute(ViewModel.Data); private void OnOpenItemClick(object sender, RoutedEventArgs e) => GetSessionViewModel().OpenAudioCommand.Execute(AppToolkit.GetSpeechPath(ViewModel.Data.Id)); diff --git a/src/Desktop/RodelAgent.UI/Controls/Base/WavePanel.xaml.cs b/src/Desktop/RodelAgent.UI/Controls/Base/WavePanel.xaml.cs index 6bb3cab0..c7bcc7c3 100644 --- a/src/Desktop/RodelAgent.UI/Controls/Base/WavePanel.xaml.cs +++ b/src/Desktop/RodelAgent.UI/Controls/Base/WavePanel.xaml.cs @@ -37,11 +37,7 @@ protected override void OnControlLoaded() { WaveCanvas.Draw += OnWaveCanvasDraw; ViewModel.RedrawWave += OnRedrawWave; - if (ViewModel.IsRecording) - { - ViewModel.StopRecordingCommand.Execute(default); - } - else if (ViewModel.IsPlaying) + if (ViewModel.IsPlaying) { ViewModel.ResetPositionCommand.Execute(default); } @@ -52,11 +48,7 @@ protected override void OnControlUnloaded() { WaveCanvas.Draw -= OnWaveCanvasDraw; ViewModel.RedrawWave -= OnRedrawWave; - if (ViewModel.IsRecording) - { - ViewModel.StopRecordingCommand.Execute(default); - } - else if (ViewModel.IsPlaying) + if (ViewModel.IsPlaying) { ViewModel.TogglePlayPauseCommand.Execute(default); } diff --git a/src/Desktop/RodelAgent.UI/Extensions/AudioFileReader.cs b/src/Desktop/RodelAgent.UI/Extensions/AudioFileReader.cs new file mode 100644 index 00000000..6aeee82f --- /dev/null +++ b/src/Desktop/RodelAgent.UI/Extensions/AudioFileReader.cs @@ -0,0 +1,147 @@ +// +using NAudio.Wave; +using NAudio.Wave.SampleProviders; + +namespace RodelAgent.UI.Extensions; + +/// +/// AudioFileReader simplifies opening an audio file in NAudio +/// Simply pass in the filename, and it will attempt to open the +/// file and set up a conversion path that turns into PCM IEEE float. +/// ACM codecs will be used for conversion. +/// It provides a volume property and implements both WaveStream and +/// ISampleProvider, making it possibly the only stage in your audio +/// pipeline necessary for simple playback scenarios +/// +public class AudioFileReader : WaveStream, ISampleProvider +{ + private WaveStream readerStream; // the waveStream which we will use for all positioning + private readonly SampleChannel sampleChannel; // sample provider that gives us most stuff we need + private readonly int destBytesPerSample; + private readonly int sourceBytesPerSample; + private readonly long length; + private readonly object lockObject; + + /// + /// Initializes a new instance of AudioFileReader + /// + /// The file to open + public AudioFileReader(string fileName) + { + lockObject = new object(); + FileName = fileName; + CreateReaderStream(fileName); + sourceBytesPerSample = (readerStream.WaveFormat.BitsPerSample / 8) * readerStream.WaveFormat.Channels; + sampleChannel = new SampleChannel(readerStream, false); + destBytesPerSample = 4 * sampleChannel.WaveFormat.Channels; + length = SourceToDest(readerStream.Length); + } + + /// + /// Creates the reader stream, supporting all filetypes in the core NAudio library, + /// and ensuring we are in PCM format + /// + /// File Name + private void CreateReaderStream(string fileName) + { + if (fileName.EndsWith(".wav", StringComparison.OrdinalIgnoreCase)) + { + readerStream = new WaveFileReader(fileName); + } + } + /// + /// File Name + /// + public string FileName { get; } + + /// + /// WaveFormat of this stream + /// + public override WaveFormat WaveFormat => sampleChannel.WaveFormat; + + /// + /// Length of this stream (in bytes) + /// + public override long Length => length; + + /// + /// Position of this stream (in bytes) + /// + public override long Position + { + get { return SourceToDest(readerStream.Position); } + set { lock (lockObject) { readerStream.Position = DestToSource(value); } } + } + + /// + /// Reads from this wave stream + /// + /// Audio buffer + /// Offset into buffer + /// Number of bytes required + /// Number of bytes read + public override int Read(byte[] buffer, int offset, int count) + { + var waveBuffer = new WaveBuffer(buffer); + int samplesRequired = count / 4; + int samplesRead = Read(waveBuffer.FloatBuffer, offset / 4, samplesRequired); + return samplesRead * 4; + } + + /// + /// Reads audio from this sample provider + /// + /// Sample buffer + /// Offset into sample buffer + /// Number of samples required + /// Number of samples read + public int Read(float[] buffer, int offset, int count) + { + lock (lockObject) + { + return sampleChannel.Read(buffer, offset, count); + } + } + + /// + /// Gets or Sets the Volume of this AudioFileReader. 1.0f is full volume + /// + public float Volume + { + get { return sampleChannel.Volume; } + set { sampleChannel.Volume = value; } + } + + /// + /// Helper to convert source to dest bytes + /// + private long SourceToDest(long sourceBytes) + { + return destBytesPerSample * (sourceBytes / sourceBytesPerSample); + } + + /// + /// Helper to convert dest to source bytes + /// + private long DestToSource(long destBytes) + { + return sourceBytesPerSample * (destBytes / destBytesPerSample); + } + + /// + /// Disposes this AudioFileReader + /// + /// True if called from Dispose + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (readerStream != null) + { + readerStream.Dispose(); + readerStream = null; + } + } + base.Dispose(disposing); + } +} diff --git a/src/Desktop/RodelAgent.UI/RodelAgent.UI.csproj b/src/Desktop/RodelAgent.UI/RodelAgent.UI.csproj index ef1539f4..e6c12189 100644 --- a/src/Desktop/RodelAgent.UI/RodelAgent.UI.csproj +++ b/src/Desktop/RodelAgent.UI/RodelAgent.UI.csproj @@ -1,7 +1,7 @@  WinExe - net8.0-windows10.0.22621.0 + net9.0-windows10.0.22621.0 10.0.19041.0 10.0.22621.38 RodelAgent.UI @@ -238,7 +238,7 @@ - + diff --git a/src/Desktop/RodelAgent.UI/ViewModels/Components/AudioWaveModuleViewModel/AudioWaveModuleViewModel.Parsers.cs b/src/Desktop/RodelAgent.UI/ViewModels/Components/AudioWaveModuleViewModel/AudioWaveModuleViewModel.Parsers.cs index 1d43fd97..863b9fb0 100644 --- a/src/Desktop/RodelAgent.UI/ViewModels/Components/AudioWaveModuleViewModel/AudioWaveModuleViewModel.Parsers.cs +++ b/src/Desktop/RodelAgent.UI/ViewModels/Components/AudioWaveModuleViewModel/AudioWaveModuleViewModel.Parsers.cs @@ -1,6 +1,6 @@ // Copyright (c) Rodel. All rights reserved. -using NAudio.Wave; +using RodelAgent.UI.Extensions; using RodelAgent.UI.Toolkits; namespace RodelAgent.UI.ViewModels.Components; @@ -62,75 +62,4 @@ await Task.Run(() => RedrawWave?.Invoke(this, EventArgs.Empty); }); } - - private void ResetRecording(string sessionId) - { - _sessionId = sessionId; - _samples.Clear(); - Seconds = 0; - var format = new WaveFormat(SampleRate, 1); - _waveFileWriter = !string.IsNullOrEmpty(_sessionId) - ? new WaveFileWriter(GetRecordingFilePath(_sessionId), format) - : default; - - var waveIn = new WaveInEvent(); - waveIn.WaveFormat = format; - waveIn.DataAvailable += async (sender, e) => - { - if (!IsRecording) - { - _dispatcherQueue.TryEnqueue(() => - { - IsRecording = true; - }); - } - - var bytesPerSample = waveIn.WaveFormat.BitsPerSample / 8; - var sampleCount = e.BytesRecorded / bytesPerSample; - var floatBuffer = new float[sampleCount]; - for (var index = 0; index < sampleCount; index++) - { - // Convert bytes to float - floatBuffer[index] = BitConverter.ToInt16(e.Buffer, index * bytesPerSample) / 32768f; - } - - _samples.AddRange(floatBuffer); - - _dispatcherQueue.TryEnqueue(() => - { - Seconds = _samples.Count / (SampleRate * 1.0); - RedrawWave?.Invoke(this, EventArgs.Empty); - }); - - if (_waveFileWriter != null) - { - await WriteFileAsync(e.Buffer, e.BytesRecorded); - } - }; - - waveIn.RecordingStopped += (sender, e) => - { - _waveIn.Dispose(); - _waveFileWriter?.Dispose(); - _waveIn = null; - _waveFileWriter = null; - - _dispatcherQueue.TryEnqueue(() => - { - IsRecording = false; - }); - }; - - _waveIn = waveIn; - } - - private async Task WriteFileAsync(byte[] buffer, int bytesRecorded) - { - if (_waveFileWriter == null) - { - return; - } - - await _waveFileWriter.WriteAsync(buffer, 0, bytesRecorded); - } } diff --git a/src/Desktop/RodelAgent.UI/ViewModels/Components/AudioWaveModuleViewModel/AudioWaveModuleViewModel.Properties.cs b/src/Desktop/RodelAgent.UI/ViewModels/Components/AudioWaveModuleViewModel/AudioWaveModuleViewModel.Properties.cs index fa5e3049..7d411be6 100644 --- a/src/Desktop/RodelAgent.UI/ViewModels/Components/AudioWaveModuleViewModel/AudioWaveModuleViewModel.Properties.cs +++ b/src/Desktop/RodelAgent.UI/ViewModels/Components/AudioWaveModuleViewModel/AudioWaveModuleViewModel.Properties.cs @@ -1,7 +1,6 @@ // Copyright (c) Rodel. All rights reserved. using Microsoft.UI.Dispatching; -using NAudio.Wave; using Windows.Media.Playback; namespace RodelAgent.UI.ViewModels.Components; @@ -15,9 +14,6 @@ public sealed partial class AudioWaveModuleViewModel private readonly DispatcherQueue _dispatcherQueue; private readonly ILogger _logger; private List _samples; - private WaveFileWriter _waveFileWriter; - private WaveInEvent _waveIn; - private string _sessionId; private MediaPlayer _mediaPlayer; private bool _isMediaEnded; diff --git a/src/Desktop/RodelAgent.UI/ViewModels/Components/AudioWaveModuleViewModel/AudioWaveModuleViewModel.cs b/src/Desktop/RodelAgent.UI/ViewModels/Components/AudioWaveModuleViewModel/AudioWaveModuleViewModel.cs index 6661db82..4ae5b75a 100644 --- a/src/Desktop/RodelAgent.UI/ViewModels/Components/AudioWaveModuleViewModel/AudioWaveModuleViewModel.cs +++ b/src/Desktop/RodelAgent.UI/ViewModels/Components/AudioWaveModuleViewModel/AudioWaveModuleViewModel.cs @@ -2,7 +2,6 @@ using System.Diagnostics; using Microsoft.UI.Dispatching; -using NAudio.Wave; using Windows.Media.Core; using Windows.Media.Playback; using Windows.Storage; @@ -92,38 +91,7 @@ private async Task LoadFileAsync(string file) [RelayCommand] private void CheckRecording() - => IsRecordingSupported = WaveIn.DeviceCount > 0; - - [RelayCommand] - private async Task StartRecordingAsync(string sessionId = default) - { - CheckRecording(); - if (!IsRecordingSupported) - { - return; - } - - if (_waveIn != null) - { - await StopRecordingAsync(); - } - - ResetRecording(sessionId); - await Task.Run(() => - { - _waveIn.StartRecording(); - }); - } - - [RelayCommand] - private async Task StopRecordingAsync() - { - Position = 0; - await Task.Run(() => - { - _waveIn?.StopRecording(); - }); - } + => IsRecordingSupported = false; [RelayCommand] private void TogglePlayPause() diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index c4a1119e..a84f6aa9 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -13,18 +13,20 @@ - + - + + + - - + + @@ -36,48 +38,49 @@ - - - - - - + + + + + + + - - + + - - - + + + + - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - + + @@ -91,7 +94,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/Libs/Migration.V1/Migration.V1.csproj b/src/Libs/Migration.V1/Migration.V1.csproj index 058d2dd1..c2faf0be 100644 --- a/src/Libs/Migration.V1/Migration.V1.csproj +++ b/src/Libs/Migration.V1/Migration.V1.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable diff --git a/src/Libs/WinUI.Share b/src/Libs/WinUI.Share index baa1b65a..1d0eef83 160000 --- a/src/Libs/WinUI.Share +++ b/src/Libs/WinUI.Share @@ -1 +1 @@ -Subproject commit baa1b65a98193dbcb905146b9f57d319d18f54e1 +Subproject commit 1d0eef8312b284377514ef1882f17846fe391c46 diff --git a/src/Libs/fluentui-emoji-bridge/fluentui-emoji-bridge.csproj b/src/Libs/fluentui-emoji-bridge/fluentui-emoji-bridge.csproj index 4ccf8672..6858b421 100644 --- a/src/Libs/fluentui-emoji-bridge/fluentui-emoji-bridge.csproj +++ b/src/Libs/fluentui-emoji-bridge/fluentui-emoji-bridge.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net9.0 fluentui_emoji_bridge latest enable diff --git a/src/Libs/semantic-kernel b/src/Libs/semantic-kernel index d38486a1..6a04e5c6 160000 --- a/src/Libs/semantic-kernel +++ b/src/Libs/semantic-kernel @@ -1 +1 @@ -Subproject commit d38486a1fb3c30e737d3520d1d0fd0274ceca0da +Subproject commit 6a04e5c675879762de8465d5a76240905c740b21 diff --git a/src/Samples/RodelAgent.Samples.Plugin/Properties/PublishProfiles/FolderProfile.pubxml b/src/Samples/RodelAgent.Samples.Plugin/Properties/PublishProfiles/FolderProfile.pubxml index de068b57..f0847075 100644 --- a/src/Samples/RodelAgent.Samples.Plugin/Properties/PublishProfiles/FolderProfile.pubxml +++ b/src/Samples/RodelAgent.Samples.Plugin/Properties/PublishProfiles/FolderProfile.pubxml @@ -6,10 +6,10 @@ https://go.microsoft.com/fwlink/?LinkID=208121. Release x64 - bin\Release\net8.0\publish\ + bin\Release\net9.0\publish\ FileSystem <_TargetId>Folder - net8.0 + net9.0 win-x64 false false diff --git a/src/Samples/RodelAgent.Samples.Plugin/RodelAgent.Samples.Plugin.csproj b/src/Samples/RodelAgent.Samples.Plugin/RodelAgent.Samples.Plugin.csproj index 1fa475d0..99e67432 100644 --- a/src/Samples/RodelAgent.Samples.Plugin/RodelAgent.Samples.Plugin.csproj +++ b/src/Samples/RodelAgent.Samples.Plugin/RodelAgent.Samples.Plugin.csproj @@ -1,7 +1,7 @@  - net8.0 + net9.0 enable enable