Architecture
Architecture
Modern Meeter is a WinUI 3 MSIX-packaged app that controls VoiceMeeter (Basic/Banana/Potato) through its native DLL API. It follows MVVM with CommunityToolkit.Mvvm source generators.
Project layout
src/
ModernMeeter/ App project (WinUI 3 MSIX)
ModernMeeter.Core/ Core library (Interop, Models, Services — no WinUI)
ModernMeeter.CmdPal/ Command Palette extension (CommandPalette SDK)
tests/
ModernMeeter.Tests/ Test project (references Core, shared-compiles app sources)
ModernMeeter.slnx Solution file
Deploy.ps1 Deployment script (local + remote)
The project was split from a single project into three so the VoiceMeeter API is reusable and the Command Palette SDK dependencies are isolated from the main app.
Layering (bottom-up)
- Interop (
ModernMeeter.Core) —LibraryImportP/Invoke toVoicemeeterRemote64.dllwith a registry-based DLL resolver. Never called directly outsideVoiceMeeterClient. - Services
- Core —
IVoiceMeeterClient/VoiceMeeterClientwrap P/Invoke into a typed C# API.AppSettingsis the settings POCO. - App —
LocalSettingsStore(IWritableOptions<AppSettings>) persists settings viaApplicationData.LocalSettings.MidiMapServicereads MIDI mapping XML.FileLoggerProviderwrites a rotating log file.
- Core —
- Models
- Core —
VoiceMeeterLayout,AudioDevice, enums (pure data, no WinUI). - App —
MidiMapEntry/MidiMessageItem(require[Bindable]for XAML DataTemplate binding).
- Core —
- ViewModels (
ModernMeeter) —MixerViewModelowns the connection and buildsStripViewModel/BusViewModelcollections;MidiViewModel,SettingsViewModel,VbanStreamViewModelhandle their respective pages. - Controls (
ModernMeeter) —BusRoutingItemobservable data object for bus routing toggles. - Views (
ModernMeeter) —MixerPage,SettingsPage,MidiPage,MidiBindingsPage,VbanPage,HelpPagehosted in aNavigationViewshell. - Command Palette (
ModernMeeter.CmdPal) —ModernMeeterExtension(IExtension) exposes mixer commands; runs as an out-of-process COM server. See Command Palette extension.
Data flow
VoiceMeeter DLL → VoiceMeeterClient → StripViewModel.Refresh()
→ [ObservableProperty] → {Binding} → UI
User input flows in reverse: property setters call SetParameter back into VoiceMeeter. A _isRefreshing guard prevents write-back loops when Refresh() updates properties.
Key design decisions
{Binding}with[Bindable]in DataTemplates —{x:Bind}crashes withE_NOINTERFACEfor CommunityToolkit.Mvvm source-generated properties in WinUI 3 (a CsWinRT marshalling issue).- Code-behind event handlers for page-level controls (Settings toggles, buttons) —
DataContextdoesn’t propagate reliably into CommunityToolkitSettingsCardcontent slots in Release builds. - Test project references
ModernMeeter.Coreand shared-compiles the remaining UI-dependent app sources, avoiding the WinAppSDK module auto-initializer that a full app project reference would pull in. FakeVoiceMeeterClientimplementsIVoiceMeeterClientso every ViewModel can be tested without the real VoiceMeeter DLL.- Self-contained deployment — bundles the .NET and Windows App SDK runtimes; a post-build target strips the WinAppRuntime framework dependency from the AppxManifest for zero-dependency installs.
- Single instance via
AppInstance.FindOrRegisterForKeyin a customProgram.csentry point. - Computed level properties (
LevelLeftPercent/LevelRightPercent) on Strip/Bus ViewModels avoidIValueConverterboxing on the 30fps level-meter hot path. Microsoft.Extensions.*throughout — Options (IWritableOptions<AppSettings>backed byLocalSettingsStore), Logging (FileLoggerProvider), and DependencyInjection (App.Services).