Skip to content

Commit 664858a

Browse files
committed
Merge branch 'dev'
2 parents 690427d + d1568fe commit 664858a

File tree

71 files changed

+1481
-609
lines changed

Some content is hidden

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

71 files changed

+1481
-609
lines changed

README.md

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,9 @@ and act as a centralised source for useful OSC programs so that a user will only
2424
Our framework supports developing your own modules to save you the trouble of having to set up everything yourself,
2525
as well as allowing other people to seamlessly use your module on their PC. See how to create a module [here](https://vrcosc.com/docs/v2/sdk/getting-started).
2626

27-
VRCOSC's powerful ChatBox design system allows you to display what you want, when you want, how you want. Check out the ChatBox-Config forum channel of our [Discord Server](https://discord.gg/vj4brHyvT5) to see some of the configs people have created!
27+
VRCOSC's powerful ChatBox design system allows you to display what you want, when you want, how you want. Check out the ChatBox-Config forum channel of our [Discord Server](https://discord.gg/vj4brHyvT5) to see some of the configs people have created or you can make your own by following [the docs](https://vrcosc.com/docs/v2/chatbox)!
2828
The ChatBox uses a [community-created list](https://github.com/cyberkitsune/chatbox-club-blacklist/blob/master/npblacklist.json) to block the ChatBox from being used in certain worlds. You can turn this off in the app settings, but we recommend you keep it on for respect.
2929

30-
Our powerful ChatBox animation system allows you to display what you want, when you want, how you want.
31-
Community configs are available, or you can make your own by following [the docs](https://vrcosc.com/docs/v2/chatbox)!
32-
3330
Featuring:
3431
- Modern GUI
3532
- Automated configuration management
@@ -44,8 +41,8 @@ Featuring:
4441

4542
## Getting Started
4643
- Download and run `VRCOSCSetup.exe` from the [Releases](https://github.com/VolcanicArts/VRCOSC/releases/latest) page
47-
- Tick the modules you'd like to use
48-
- (Optional) Download any prefabs you want and add them to your avatar (Guides are available inside each prefab)
44+
- Enable the modules you'd like to use
45+
- (Optional) Download any prefabs you want and add them to your avatar from [here](https://vrcosc.com/docs/downloads#prefabs)
4946
- Press the run button!
5047

5148
Check the [FAQ](https://vrcosc.com/docs/faq) if you have any issues with installing, using the app, or using any of the prefabs.
@@ -84,4 +81,4 @@ The official modules source code is located [here](https://github.com/VolcanicAr
8481
## License
8582
This program is licensed under the [GNU General Public License V3](https://www.gnu.org/licenses/gpl-3.0.en.html). Please see [the license file](LICENSE) for more information.
8683

87-
Other libraries included in this project may contain different licenses. See the license files in their repos for more information.
84+
Other libraries included in this project may contain different licenses. See the license files in their repos for more information.

VRCOSC.App/AppManager.cs

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
using VRCOSC.App.Startup;
3434
using VRCOSC.App.UI.Themes;
3535
using VRCOSC.App.UI.Windows;
36-
using VRCOSC.App.Updater;
3736
using VRCOSC.App.Utils;
3837
using VRCOSC.App.VRChatAPI;
3938
using Module = VRCOSC.App.SDK.Modules.Module;
@@ -59,7 +58,6 @@ public class AppManager
5958
public Observable<AppManagerState> State { get; } = new(AppManagerState.Stopped);
6059
public Observable<Theme> ProxyTheme { get; } = new(Theme.Dark);
6160

62-
public VelopackUpdater VelopackUpdater = null!;
6361
public ConnectionManager ConnectionManager = null!;
6462
public VRChatOscClient VRChatOscClient = null!;
6563
public VRChatClient VRChatClient = null!;
@@ -87,7 +85,6 @@ public void Initialise()
8785
{
8886
SettingsManager.GetInstance().GetObservable<Theme>(VRCOSCSetting.Theme).Subscribe(theme => ProxyTheme.Value = theme, true);
8987

90-
VelopackUpdater = new VelopackUpdater();
9188
ConnectionManager = new ConnectionManager();
9289
VRChatOscClient = new VRChatOscClient();
9390
VRChatClient = new VRChatClient(VRChatOscClient);
@@ -155,16 +152,14 @@ public void InitialLoadComplete()
155152
VRChatOscClient.Init(ConnectionManager);
156153
ConnectionManager.Init();
157154

158-
vrchatCheckTask = new Repeater(checkForVRChatAutoStart);
155+
vrchatCheckTask = new Repeater($"{nameof(AppManager)}-{nameof(checkForVRChatAutoStart)}", checkForVRChatAutoStart);
159156
vrchatCheckTask.Start(TimeSpan.FromSeconds(2));
160157

161-
openvrCheckTask = new Repeater(checkForOpenVR);
158+
openvrCheckTask = new Repeater($"{nameof(AppManager)}-{nameof(checkForOpenVR)}", checkForOpenVR);
162159
openvrCheckTask.Start(TimeSpan.FromSeconds(2));
163160

164-
openvrUpdateTask = new Repeater(updateOVRClient);
161+
openvrUpdateTask = new Repeater($"{nameof(AppManager)}-{nameof(updateOVRClient)}", updateOVRClient);
165162
openvrUpdateTask.Start(TimeSpan.FromSeconds(1d / 60d));
166-
167-
VelopackUpdater.ShowUpdateIfAvailable();
168163
}
169164

170165
private void updateOVRClient()
@@ -241,9 +236,9 @@ private void processOscMessageQueue()
241236
if (wasPlayerUpdated) ModuleManager.GetInstance().PlayerUpdate();
242237

243238
if (message.ParameterName.StartsWith("VRCOSC/Controls")) handleControlParameter(new ReceivedParameter(message.ParameterName, message.ParameterValue));
244-
}
245239

246-
ModuleManager.GetInstance().ParameterReceived(message);
240+
ModuleManager.GetInstance().ParameterReceived(message);
241+
}
247242
}
248243
}
249244

@@ -262,7 +257,7 @@ private void sendMetadataParameters()
262257

263258
private void handleControlParameter(ReceivedParameter parameter)
264259
{
265-
if (parameter.Name == "VRCOSC/Controls/ChatBox/Enabled" && parameter.IsValueType<bool>())
260+
if (parameter is { Name: "VRCOSC/Controls/ChatBox/Enabled", Type: ParameterType.Bool })
266261
{
267262
ChatBoxManager.GetInstance().SendEnabled = parameter.GetValue<bool>();
268263
}
@@ -423,14 +418,14 @@ private async Task startAsync()
423418

424419
if (result == MessageBoxResult.Yes)
425420
{
426-
await installSpeechModel();
421+
await InstallSpeechModel();
427422
}
428423
}
429424

430425
SpeechEngine.Initialise();
431426
}
432427

433-
updateTask = new Repeater(update);
428+
updateTask = new Repeater($"{nameof(AppManager)}-{nameof(update)}", update);
434429
updateTask.Start(TimeSpan.FromSeconds(1d / 60d));
435430

436431
VRChatOscClient.OnParameterReceived += onParameterReceived;
@@ -442,14 +437,12 @@ private async Task startAsync()
442437
sendControlParameters();
443438
}
444439

445-
private Task installSpeechModel()
440+
public Task InstallSpeechModel() => Application.Current.Dispatcher.Invoke(() =>
446441
{
447-
var action = new FileDownloadAction(new Uri("https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-tiny.bin?download=true"), Storage.GetStorageForDirectory("runtime/whisper"), "ggml-tiny.bin");
448-
449-
action.OnComplete += () => { SettingsManager.GetInstance().GetObservable<string>(VRCOSCSetting.SpeechModelPath).Value = Storage.GetStorageForDirectory("runtime/whisper").GetFullPath("ggml-tiny.bin"); };
450-
442+
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");
443+
action.OnComplete += () => SettingsManager.GetInstance().GetObservable<string>(VRCOSCSetting.SpeechModelPath).Value = Storage.GetStorageForDirectory("runtime/whisper").GetFullPath("ggml-small.bin");
451444
return MainWindow.GetInstance().ShowLoadingOverlay("Installing Model", action);
452-
}
445+
});
453446

454447
private void initialiseOSCClient(IPAddress sendAddress, int sendPort, IPAddress receiveAddress, int receivePort)
455448
{

VRCOSC.App/Audio/Whisper/AudioProcessor.cs

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -15,51 +15,67 @@ namespace VRCOSC.App.Audio.Whisper;
1515
internal class AudioProcessor
1616
{
1717
private readonly AudioCapture? audioCapture;
18-
private readonly WhisperProcessor? whisper;
18+
private WhisperProcessor? whisper;
1919

2020
private const int default_samples_to_check = 24000; // sample rate is 16000 so check the last 1.5 seconds of audio
2121

2222
private SpeechResult? speechResult;
2323
private bool isProcessing;
2424

2525
public AudioProcessor(MMDevice device)
26+
{
27+
try
28+
{
29+
audioCapture = new AudioCapture(device);
30+
}
31+
catch (Exception e)
32+
{
33+
audioCapture = null;
34+
ExceptionHandler.Handle(e);
35+
}
36+
}
37+
38+
private void buildWhisperProcessor()
2639
{
2740
var modelFilePath = SettingsManager.GetInstance().GetValue<string>(VRCOSCSetting.SpeechModelPath);
2841

2942
try
3043
{
31-
var builder = WhisperFactory.FromPath(modelFilePath);
44+
var builder = WhisperFactory.FromPath(modelFilePath).CreateBuilder();
3245

33-
whisper = builder.CreateBuilder()
34-
.WithProbabilities()
46+
builder = builder.WithProbabilities()
3547
.WithThreads(8)
3648
.WithNoContext()
3749
.WithSingleSegment()
3850
.WithMaxSegmentLength(int.MaxValue)
39-
.Build();
51+
.WithLanguageDetection();
52+
53+
if (SettingsManager.GetInstance().GetValue<bool>(VRCOSCSetting.SpeechTranslate))
54+
{
55+
builder.WithLanguage("en");
56+
}
57+
58+
// translation for any-to-any technically works but is unsupported
59+
// for future reference, to get any-to-any to work you have to do:
60+
// WithLanguageDetection
61+
// WithLanguage(targetLanguage)
62+
63+
whisper = builder.Build();
4064
}
4165
catch (Exception e)
4266
{
4367
whisper = null;
4468
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'");
4569
}
46-
47-
try
48-
{
49-
audioCapture = new AudioCapture(device);
50-
}
51-
catch (Exception e)
52-
{
53-
audioCapture = null;
54-
ExceptionHandler.Handle(e);
55-
}
5670
}
5771

5872
public void Start()
5973
{
6074
speechResult = null;
6175
isProcessing = false;
6276

77+
buildWhisperProcessor();
78+
6379
if (whisper is null || audioCapture is null) return;
6480

6581
audioCapture.ClearBuffer();
@@ -69,6 +85,8 @@ public void Start()
6985
public void Stop()
7086
{
7187
audioCapture?.StopCapture();
88+
whisper?.Dispose();
89+
whisper = null;
7290
}
7391

7492
public async Task<SpeechResult?> GetResultAsync()
@@ -95,9 +113,7 @@ public void Stop()
95113

96114
if (finalSpeechResult is not null)
97115
{
98-
#if DEBUG
99-
Logger.Log($"Final result: {finalSpeechResult.Text} - {finalSpeechResult.Confidence}");
100-
#endif
116+
Logger.Log($"Final result: {finalSpeechResult.Text} - {finalSpeechResult.Confidence}", LoggingTarget.Information);
101117
}
102118

103119
speechResult = null;
@@ -110,9 +126,7 @@ public void Stop()
110126
speechResult = await processWithWhisper(data, false);
111127
isProcessing = false;
112128

113-
#if DEBUG
114-
Logger.Log($"Result: {speechResult?.Text}");
115-
#endif
129+
Logger.Log($"Result: {speechResult?.Text}", LoggingTarget.Information);
116130

117131
return speechResult;
118132
}
@@ -150,9 +164,7 @@ private bool isSilent(float[] buffer)
150164
}
151165

152166
var rms = Math.Sqrt(sum / samplesToCheck);
153-
#if DEBUG
154-
Logger.Log($"RMS: {rms}");
155-
#endif
167+
Logger.Log($"RMS: {rms}", LoggingTarget.Information);
156168
return rms < SettingsManager.GetInstance().GetValue<float>(VRCOSCSetting.SpeechNoiseCutoff);
157169
}
158170

VRCOSC.App/Audio/Whisper/WhisperSpeechEngine.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ private async void onCaptureDeviceIdChanged(string newDeviceId)
6666
audioProcessor = new AudioProcessor(captureDevice);
6767
audioProcessor.Start();
6868

69-
repeater = new Repeater(processResult);
69+
repeater = new Repeater($"{nameof(WhisperSpeechEngine)}-{nameof(processResult)}", processResult);
7070
// Do not change this from 1.5
7171
repeater.Start(TimeSpan.FromSeconds(1.5f));
7272
}
@@ -81,7 +81,7 @@ private async void processResult()
8181
if (result is null) return;
8282

8383
// filter out things like [BLANK AUDIO]
84-
if (result.Text.StartsWith('[') || result.Text.Contains('*')) return;
84+
if (result.Text.StartsWith('[')) return;
8585

8686
var requiredConfidence = SettingsManager.GetInstance().GetValue<float>(VRCOSCSetting.SpeechConfidence);
8787
if (result.Confidence < requiredConfidence) return;

VRCOSC.App/ChatBox/ChatBoxManager.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,8 @@ public void Start()
198198
var sendInterval = SettingsManager.GetInstance().GetValue<int>(VRCOSCSetting.ChatBoxSendInterval);
199199

200200
startTime = DateTimeOffset.Now;
201-
sendTask = new Repeater(chatBoxUpdate);
202-
updateTask = new Repeater(update);
201+
sendTask = new Repeater($"{nameof(ChatBoxManager)}-{nameof(chatBoxUpdate)}", chatBoxUpdate);
202+
updateTask = new Repeater($"{nameof(ChatBoxManager)}-{nameof(update)}", update);
203203
SendEnabled = true;
204204
isClear = true;
205205
currentIsTyping = false;

VRCOSC.App/ChatBox/Clips/Clip.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) VolcanicArts. Licensed under the GPL-3.0 License.
1+
// Copyright (c) VolcanicArts. Licensed under the GPL-3.0 License.
22
// See the LICENSE file in the repository root for full license text.
33

44
using System;
@@ -10,6 +10,7 @@
1010
using System.Runtime.CompilerServices;
1111
using VRCOSC.App.ChatBox.Clips.Variables;
1212
using VRCOSC.App.Modules;
13+
using VRCOSC.App.Settings;
1314
using VRCOSC.App.Utils;
1415

1516
namespace VRCOSC.App.ChatBox.Clips;
@@ -47,7 +48,7 @@ public Dictionary<string, List<ClipVariableReference>> UIVariables
4748
ChatBoxManager.GetInstance().VariableReferences.Where(clipVariableReference => clipVariableReference.ModuleID is null).OrderBy(reference => reference.DisplayName.Value).ForEach(clipVariableReference => builtInVariables.Add(clipVariableReference));
4849
finalDict.Add("Built-In", builtInVariables);
4950

50-
var modules = LinkedModules.Select(moduleID => ModuleManager.GetInstance().GetModuleOfID(moduleID)).OrderBy(module => module.Title);
51+
var modules = LinkedModules.Select(moduleID => ModuleManager.GetInstance().GetModuleOfID(moduleID)).Where(module => module.Enabled.Value || !SettingsManager.GetInstance().GetValue<bool>(VRCOSCSetting.FilterByEnabledModules)).OrderBy(module => module.Title);
5152

5253
foreach (var module in modules)
5354
{
@@ -58,6 +59,11 @@ public Dictionary<string, List<ClipVariableReference>> UIVariables
5859
}
5960
}
6061

62+
public void UpdateUI()
63+
{
64+
OnPropertyChanged(nameof(UIVariables));
65+
}
66+
6167
public bool HasStates => States.Any();
6268
public bool HasEvents => Events.Any();
6369

VRCOSC.App/ChatBox/Clips/ClipEvent.cs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) VolcanicArts. Licensed under the GPL-3.0 License.
1+
// Copyright (c) VolcanicArts. Licensed under the GPL-3.0 License.
22
// See the LICENSE file in the repository root for full license text.
33

44
using System;
@@ -47,13 +47,22 @@ public override bool ShouldBeVisible
4747
{
4848
get
4949
{
50-
if (!SettingsManager.GetInstance().GetValue<bool>(VRCOSCSetting.ShowRelevantElementsOnly)) return true;
51-
52-
var selectedClip = MainWindow.GetInstance().ChatBoxView.SelectedClip;
53-
Debug.Assert(selectedClip is not null);
54-
55-
var enabledModuleIDs = ModuleManager.GetInstance().GetEnabledModuleIDs().Where(moduleID => selectedClip.LinkedModules.Contains(moduleID)).OrderBy(moduleID => moduleID);
56-
return enabledModuleIDs.Contains(ModuleID);
50+
if (SettingsManager.GetInstance().GetValue<bool>(VRCOSCSetting.FilterByEnabledModules))
51+
{
52+
var selectedClip = MainWindow.GetInstance().ChatBoxView.SelectedClip;
53+
Debug.Assert(selectedClip is not null);
54+
55+
var enabledModuleIDs = ModuleManager.GetInstance().GetEnabledModuleIDs().Where(moduleID => selectedClip.LinkedModules.Contains(moduleID)).OrderBy(moduleID => moduleID);
56+
return enabledModuleIDs.Contains(ModuleID);
57+
}
58+
else
59+
{
60+
var selectedClip = MainWindow.GetInstance().ChatBoxView.SelectedClip;
61+
Debug.Assert(selectedClip is not null);
62+
63+
var enabledModuleIDs = ModuleManager.GetInstance().Modules.Values.SelectMany(moduleList => moduleList).Where(module => selectedClip.LinkedModules.Contains(module.FullID)).Select(module => module.FullID).OrderBy(moduleID => moduleID);
64+
return enabledModuleIDs.Contains(ModuleID);
65+
}
5766
}
5867
}
5968

VRCOSC.App/ChatBox/Clips/ClipState.cs

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) VolcanicArts. Licensed under the GPL-3.0 License.
1+
// Copyright (c) VolcanicArts. Licensed under the GPL-3.0 License.
22
// See the LICENSE file in the repository root for full license text.
33

44
using System;
@@ -54,14 +54,24 @@ public override bool ShouldBeVisible
5454
{
5555
if (IsBuiltIn) return true;
5656

57-
if (!SettingsManager.GetInstance().GetValue<bool>(VRCOSCSetting.ShowRelevantElementsOnly)) return true;
58-
59-
var selectedClip = MainWindow.GetInstance().ChatBoxView.SelectedClip;
60-
Debug.Assert(selectedClip is not null);
57+
if (SettingsManager.GetInstance().GetValue<bool>(VRCOSCSetting.FilterByEnabledModules))
58+
{
59+
var selectedClip = MainWindow.GetInstance().ChatBoxView.SelectedClip;
60+
Debug.Assert(selectedClip is not null);
61+
62+
var enabledModuleIDs = ModuleManager.GetInstance().GetEnabledModuleIDs().Where(moduleID => selectedClip.LinkedModules.Contains(moduleID)).OrderBy(moduleID => moduleID);
63+
var clipStateModuleIDs = States.Select(pair => pair.Key).OrderBy(s => s);
64+
return enabledModuleIDs.SequenceEqual(clipStateModuleIDs);
65+
}
66+
else
67+
{
68+
var selectedClip = MainWindow.GetInstance().ChatBoxView.SelectedClip;
69+
Debug.Assert(selectedClip is not null);
6170

62-
var enabledModuleIDs = ModuleManager.GetInstance().GetEnabledModuleIDs().Where(moduleID => selectedClip.LinkedModules.Contains(moduleID)).OrderBy(moduleID => moduleID);
63-
var clipStateModuleIDs = States.Select(pair => pair.Key).OrderBy(s => s);
64-
return enabledModuleIDs.SequenceEqual(clipStateModuleIDs);
71+
var enabledModuleIDs = ModuleManager.GetInstance().Modules.Values.SelectMany(moduleList => moduleList).Where(module => selectedClip.LinkedModules.Contains(module.FullID)).Select(module => module.FullID).OrderBy(moduleID => moduleID);
72+
var clipStateModuleIDs = States.Select(pair => pair.Key).OrderBy(s => s);
73+
return enabledModuleIDs.SequenceEqual(clipStateModuleIDs);
74+
}
6575
}
6676
}
6777

0 commit comments

Comments
 (0)