Skip to content

Commit 591dec4

Browse files
committed
Merge branch 'dev'
2 parents c80ea93 + 30aa055 commit 591dec4

File tree

115 files changed

+2755
-2105
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

115 files changed

+2755
-2105
lines changed

VRCOSC.App/AppManager.cs

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -464,16 +464,23 @@ private async Task startAsync()
464464
{
465465
if (ModuleManager.GetInstance().GetEnabledModulesOfType<ISpeechHandler>().Any() && SettingsManager.GetInstance().GetValue<bool>(VRCOSCSetting.SpeechEnabled))
466466
{
467-
if (string.IsNullOrWhiteSpace(SettingsManager.GetInstance().GetValue<string>(VRCOSCSetting.SpeechModelPath)))
467+
if (SettingsManager.GetInstance().GetValue<SpeechModel>(VRCOSCSetting.SpeechModel) == SpeechModel.Custom && string.IsNullOrWhiteSpace(SettingsManager.GetInstance().GetValue<string>(VRCOSCSetting.SpeechModelPath)))
468468
{
469469
var result = MessageBox.Show("You have enabled modules that require the speech engine.\nWould you like to automatically set it up?", "Set Up Speech Engine?", MessageBoxButton.YesNo);
470470

471471
if (result == MessageBoxResult.Yes)
472472
{
473-
await InstallSpeechModel();
473+
await InstallSpeechModel(SpeechModel.Small);
474+
}
475+
else
476+
{
477+
SettingsManager.GetInstance().GetObservable<bool>(VRCOSCSetting.SpeechEnabled).Value = false;
474478
}
475479
}
480+
}
476481

482+
if (ModuleManager.GetInstance().GetEnabledModulesOfType<ISpeechHandler>().Any() && SettingsManager.GetInstance().GetValue<bool>(VRCOSCSetting.SpeechEnabled))
483+
{
477484
SpeechEngine.Initialise();
478485
}
479486

@@ -499,10 +506,19 @@ private async Task startAsync()
499506
sendControlParameters();
500507
}
501508

502-
public Task InstallSpeechModel() => Application.Current.Dispatcher.Invoke(() =>
509+
public Task InstallSpeechModel(SpeechModel model) => Application.Current.Dispatcher.Invoke(() =>
503510
{
504-
var action = new FileDownloadAction(new Uri("https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-small.bin?download=true"), Storage.GetStorageForDirectory("runtime/whisper"), "ggml-small.bin");
505-
action.OnComplete += () => SettingsManager.GetInstance().GetObservable<string>(VRCOSCSetting.SpeechModelPath).Value = Storage.GetStorageForDirectory("runtime/whisper").GetFullPath("ggml-small.bin");
511+
var modelName = model switch
512+
{
513+
SpeechModel.Tiny => "ggml-tiny.bin",
514+
SpeechModel.Small => "ggml-small.bin",
515+
_ => throw new ArgumentOutOfRangeException(nameof(model), model, null)
516+
};
517+
518+
var action = new FileDownloadAction(new Uri($"https://huggingface.co/ggerganov/whisper.cpp/resolve/main/{modelName}?download=true"), Storage.GetStorageForDirectory("runtime/whisper"), modelName);
519+
520+
action.OnComplete += () => SettingsManager.GetInstance().GetObservable<SpeechModel>(VRCOSCSetting.SpeechModel).Value = model;
521+
506522
return MainWindow.GetInstance().ShowLoadingOverlay(action);
507523
});
508524

@@ -557,7 +573,7 @@ public async Task StopAsync()
557573
await ChatBoxManager.GetInstance().Stop();
558574
VRChatClient.Teardown();
559575
VRChatOscClient.DisableSend();
560-
RouterManager.GetInstance().Stop();
576+
await RouterManager.GetInstance().Stop();
561577

562578
lock (oscMessageQueueLock)
563579
{

VRCOSC.App/Audio/AudioCapture.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ internal class AudioCapture
1717

1818
public bool IsCapturing => capture.CaptureState == CaptureState.Capturing;
1919

20+
public Action? OnNewDataAvailable;
21+
2022
public AudioCapture(MMDevice device)
2123
{
2224
capture = new WasapiCapture(device)
@@ -38,6 +40,7 @@ public void StartCapture()
3840
public void StopCapture()
3941
{
4042
capture.StopRecording();
43+
ClearBuffer();
4144
}
4245

4346
private void OnDataAvailable(object? sender, WaveInEventArgs e)
@@ -46,6 +49,8 @@ private void OnDataAvailable(object? sender, WaveInEventArgs e)
4649
{
4750
buffer.Write(e.Buffer, 0, e.BytesRecorded);
4851
}
52+
53+
OnNewDataAvailable?.Invoke();
4954
}
5055

5156
private void OnRecordingStopped(object? sender, StoppedEventArgs e)

VRCOSC.App/Audio/Whisper/AudioProcessor.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,15 @@ public AudioProcessor(MMDevice device)
3737

3838
private void buildWhisperProcessor()
3939
{
40-
var modelFilePath = SettingsManager.GetInstance().GetValue<string>(VRCOSCSetting.SpeechModelPath);
40+
var speechModel = SettingsManager.GetInstance().GetValue<SpeechModel>(VRCOSCSetting.SpeechModel);
41+
42+
var modelFilePath = speechModel switch
43+
{
44+
SpeechModel.Custom => SettingsManager.GetInstance().GetValue<string>(VRCOSCSetting.SpeechModelPath),
45+
SpeechModel.Tiny => AppManager.GetInstance().Storage.GetFullPath("runtime/whisper/ggml-tiny.bin"),
46+
SpeechModel.Small => AppManager.GetInstance().Storage.GetFullPath("runtime/whisper/ggml-small.bin"),
47+
_ => throw new ArgumentOutOfRangeException()
48+
};
4149

4250
try
4351
{
@@ -65,7 +73,7 @@ private void buildWhisperProcessor()
6573
catch (Exception e)
6674
{
6775
whisper = null;
68-
ExceptionHandler.Handle(e, "The Whisper model path is empty or incorrect. Please go into the app's speech settings and restore the model by clicking 'Auto Install Model'");
76+
ExceptionHandler.Handle(e, "The Whisper model path is empty or incorrect. Please go into the app's speech settings and select a model");
6977
}
7078
}
7179

VRCOSC.App/MainApp.xaml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<Application x:Class="VRCOSC.App.MainApp"
22
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
33
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4-
xmlns:core="clr-namespace:VRCOSC.App.UI.Core"
54
xmlns:themes="clr-namespace:VRCOSC.App.UI.Themes">
65
<Application.Resources>
76
<ResourceDictionary>
@@ -18,11 +17,6 @@
1817
<ResourceDictionary Source="UI/Styles/KeybindPickerStyle.xaml" />
1918
<ResourceDictionary Source="UI/Styles/VRCOSCSliderStyle.xaml" />
2019
</ResourceDictionary.MergedDictionaries>
21-
<Style TargetType="{x:Type core:IPPortTextBox}" BasedOn="{StaticResource {x:Type TextBox}}" />
22-
<Style TargetType="Window">
23-
<Setter Property="Background" Value="Black" />
24-
<Setter Property="AllowsTransparency" Value="False"/>
25-
</Style>
2620
</ResourceDictionary>
2721
</Application.Resources>
2822
</Application>

VRCOSC.App/Modules/ModuleManager.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using System.Runtime.Loader;
1111
using System.Text;
1212
using System.Threading.Tasks;
13+
using Windows.Win32;
1314
using VRCOSC.App.ChatBox;
1415
using VRCOSC.App.Modules.Serialisation;
1516
using VRCOSC.App.OSC.VRChat;
@@ -140,6 +141,7 @@ public void LoadAllModules(Dictionary<string, string>? filePathOverrides = null)
140141

141142
loadLocalModules();
142143
loadRemoteModules();
144+
PInvoke.SetDllDirectory((string?)null);
143145

144146
foreach (var module in modules)
145147
{
@@ -362,6 +364,8 @@ private List<Module> retrieveModuleInstances(string packageId, AssemblyLoadConte
362364
private AssemblyLoadContext loadContextFromPath(string path)
363365
{
364366
var assemblyLoadContext = new AssemblyLoadContext(null, true);
367+
PInvoke.SetDllDirectory(path);
368+
365369
foreach (var dllPath in Directory.GetFiles(path, "*.dll")) loadAssemblyFromPath(assemblyLoadContext, dllPath);
366370
return assemblyLoadContext;
367371
}

VRCOSC.App/Modules/Serialisation/ModuleSerialiser.cs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,16 @@
22
// See the LICENSE file in the repository root for full license text.
33

44
using System;
5+
using System.Collections.Generic;
56
using System.IO;
7+
using System.Reflection;
8+
using Semver;
9+
using VRCOSC.App.Packages;
610
using VRCOSC.App.SDK.Modules;
711
using VRCOSC.App.SDK.Modules.Attributes.Settings;
812
using VRCOSC.App.Serialisation;
913
using VRCOSC.App.Utils;
14+
using Module = VRCOSC.App.SDK.Modules.Module;
1015

1116
namespace VRCOSC.App.Modules.Serialisation;
1217

@@ -26,10 +31,50 @@ protected override bool ExecuteAfterDeserialisation(SerialisableModule data)
2631

2732
Reference.Enabled.Value = data.Enabled;
2833

34+
var clonedSettings = new Dictionary<string, object?>(data.Settings);
35+
2936
foreach (var settingPair in data.Settings)
3037
{
3138
var (settingKey, settingValue) = settingPair;
3239

40+
var savedVersion = data.PackageVersion is not null ? SemVersion.Parse(data.PackageVersion) : new SemVersion(0);
41+
var latestVersion = PackageManager.GetInstance().GetInstalledVersion(Reference.PackageID);
42+
43+
while (savedVersion != latestVersion)
44+
{
45+
if (Reference.Migrators.TryGetValue(settingKey, out var migrator))
46+
{
47+
if (migrator.TryGetValue(savedVersion, out MethodInfo? info))
48+
{
49+
var attribute = info.GetCustomAttribute<ModuleMigrationAttribute>()!;
50+
var sourceType = info.GetParameters()[0].ParameterType;
51+
52+
if (TryConvertToTargetType(settingValue, sourceType, out var convertedValue))
53+
{
54+
settingValue = info.Invoke(Reference, [convertedValue]);
55+
settingKey = attribute.DestinationSetting;
56+
savedVersion = attribute.DestinationVersion;
57+
shouldReserialise = true;
58+
}
59+
}
60+
else
61+
{
62+
break;
63+
}
64+
}
65+
else
66+
{
67+
break;
68+
}
69+
}
70+
71+
clonedSettings[settingKey] = settingValue;
72+
}
73+
74+
foreach (var settingPair in clonedSettings)
75+
{
76+
var (settingKey, settingValue) = settingPair;
77+
3378
try
3479
{
3580
var setting = Reference.GetSetting<ModuleSetting>(settingKey);

VRCOSC.App/Modules/Serialisation/SerialisableModule.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Collections.Generic;
55
using System.Linq;
66
using Newtonsoft.Json;
7+
using VRCOSC.App.Packages;
78
using VRCOSC.App.SDK.Modules;
89
using VRCOSC.App.Serialisation;
910
using VRCOSC.App.Utils;
@@ -12,6 +13,9 @@ namespace VRCOSC.App.Modules.Serialisation;
1213

1314
public class SerialisableModule : SerialisableVersion
1415
{
16+
[JsonProperty("package_version")]
17+
public string? PackageVersion;
18+
1519
[JsonProperty("enabled")]
1620
public bool Enabled;
1721

@@ -29,6 +33,7 @@ public SerialisableModule()
2933
public SerialisableModule(Module module)
3034
{
3135
Version = 1;
36+
PackageVersion = PackageManager.GetInstance().GetInstalledVersion(module.PackageID).ToString();
3237

3338
Enabled = module.Enabled.Value;
3439
module.Settings.Where(pair => !pair.Value.InternalIsDefault()).ForEach(pair => Settings.Add(pair.Key, pair.Value.InternalSerialise()));

VRCOSC.App/NativeMethods.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ CoTaskMemFree
1212
GetDpiForSystem
1313
MonitorFromWindow
1414
GetMonitorInfoW
15-
DwmSetWindowAttribute
15+
DwmSetWindowAttribute
16+
SetDllDirectory

VRCOSC.App/OVR/OVRDeviceManager.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ public void AddOrUpdateDeviceRole(string serialNumber, DeviceRole deviceRole)
4747
if (TrackedDevices.TryGetValue(serialNumber, out var device))
4848
{
4949
index = device.Index;
50+
if (device.Role == deviceRole) return;
51+
5052
Logger.Log($"Updating {serialNumber} to role {deviceRole}");
5153
}
5254
else
@@ -183,4 +185,4 @@ private void auditGenericTrackedDevices()
183185
addTrackedDevice<TrackedDevice>(connectedGenericDeviceSerial, DeviceRole.Unset, connectedGenericDeviceIndex);
184186
}
185187
}
186-
}
188+
}

VRCOSC.App/Packages/PackageManager.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Threading.Tasks;
1010
using System.Windows;
1111
using Octokit;
12+
using Semver;
1213
using VRCOSC.App.Modules;
1314
using VRCOSC.App.Packages.Serialisation;
1415
using VRCOSC.App.Serialisation;
@@ -177,13 +178,13 @@ public async Task UninstallPackage(PackageSource packageSource)
177178

178179
public bool IsInstalled(PackageSource packageSource) => packageSource.PackageID is not null && InstalledPackages.ContainsKey(packageSource.PackageID);
179180
public string GetInstalledVersion(PackageSource packageSource) => packageSource.PackageID is not null && InstalledPackages.TryGetValue(packageSource.PackageID, out var version) ? version : string.Empty;
181+
public SemVersion GetInstalledVersion(string packageId) => packageId == "local" ? new SemVersion(0) : SemVersion.Parse(InstalledPackages[packageId], SemVersionStyles.Any);
180182

181183
private async Task loadCommunityPackages()
182184
{
183185
var repos = await GitHubProxy.Client.Search.SearchRepo(new SearchRepositoriesRequest
184186
{
185-
Topic = community_tag,
186-
Fork = ForkQualifier.IncludeForks
187+
Topic = community_tag
187188
}).WaitAsync(TimeSpan.FromSeconds(5));
188189

189190
foreach (var repo in repos.Items.Where(repo => repo.Name != "VRCOSC"))

VRCOSC.App/Packages/PackageSource.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,9 @@ public bool IsUpdateAvailable()
6060
{
6161
if (InstalledRelease?.IsPreRelease ?? false) return null;
6262

63-
var latestNonPreRelease = filterReleases(true, false).First();
63+
var latestNonPreRelease = filterReleases(true, false).FirstOrDefault();
64+
if (latestNonPreRelease is null) return null;
65+
6466
var installedVersion = SemVersion.Parse(InstalledVersion, SemVersionStyles.Any);
6567
var latestNonPreReleaseVersion = SemVersion.Parse(latestNonPreRelease.Version, SemVersionStyles.Any);
6668
return SemVersion.ComparePrecedence(latestNonPreReleaseVersion, installedVersion) == 1 ? latestNonPreRelease : null;

VRCOSC.App/Router/RouterInstance.cs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@
22
// See the LICENSE file in the repository root for full license text.
33

44
using System.Net;
5-
using Newtonsoft.Json;
65
using VRCOSC.App.Utils;
76

87
namespace VRCOSC.App.Router;
98

109
public class RouterInstance
1110
{
12-
[JsonProperty("name")]
13-
public Observable<string> Name { get; } = new("My Label");
14-
15-
[JsonProperty("endpoint")]
11+
public Observable<string> Name { get; } = new("My Router Instance");
12+
public Observable<RouterMode> Mode { get; } = new(RouterMode.Send);
1613
public Observable<string> Endpoint { get; } = new($"{IPAddress.Loopback}:9000");
1714
}
15+
16+
public enum RouterMode
17+
{
18+
Send,
19+
Receive
20+
}

0 commit comments

Comments
 (0)