This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
OpenUtau is a cross-platform (Windows/macOS/Linux) singing voice synthesis editor for the UTAU community. It is a .NET 8 desktop application built with Avalonia (UI) and a large core library that handles voicebanks, phonemization, and multiple audio rendering backends. This fork ("HifiNeura") is actively developing the HIFI-NEURA neural phrase renderer (see OpenUtau.Core/HifiNeural/).
# Restore dependencies (run from repo root)
dotnet restore OpenUtau
# Run the app (Debug)
dotnet run --project OpenUtau
# Run all tests
dotnet test OpenUtau.Test
# Run a single test class / method (xUnit filter)
dotnet test OpenUtau.Test --filter "FullyQualifiedName~ClassName"
dotnet test OpenUtau.Test --filter "FullyQualifiedName~ClassName.MethodName"
# Publish a self-contained build for a specific runtime (rid: win-x64, osx-arm64, linux-x64, ...)
dotnet publish OpenUtau -c Release -r win-x64 --self-contained true -o bin/win-x64/Notes:
dotnet testbuilds the whole solution first, so it is the quickest way to verify a change compiles end-to-end.- The
OpenUtauapp project compiles withTreatWarningsAsErrors=true鈥?warnings will fail the build.OpenUtau.Coredoes not. - On Windows the app targets
net8.0-windowsand usesMicrosoft.ML.OnnxRuntime.DirectML; elsewhere it targetsnet8.0and uses the plainMicrosoft.ML.OnnxRuntime. Code guarded by Windows-only APIs uses theWINDOWScompile constant. - Native libraries (resamplers, worldline, etc.) live under
runtimes/<rid>/native/and are copied to output per-RID.
The solution (OpenUtau.sln) has four projects:
- OpenUtau.Core 鈥?Engine and business logic. No UI dependency. Contains the document model, command system, rendering backends, phonemizer API, and format I/O.
- OpenUtau 鈥?Avalonia desktop UI (MVVM via ReactiveUI). Views (
.axaml) + ViewModels. Depends on Core and Plugin.Builtin. - OpenUtau.Plugin.Builtin 鈥?Built-in phonemizers (one class per language/method, e.g.
JapaneseVCVPhonemizer,ArpasingPhonemizer). Loaded by reflection at runtime. - OpenUtau.Test 鈥?xUnit tests. Uses
Avalonia.Headless.XUnitfor UI-touching tests. Test fixtures live inUsts/andFiles/.
DocManager(OpenUtau.Core/DocManager.cs) is a singleton holding the currentUProject. It owns the undo/redo command queue and a pub/sub notification bus.- All mutations to the project go through
UCommandsubclasses (OpenUtau.Core/Commands/). A command implementsExecute()/Unexecute(). UI and editing code never mutate the model directly. - Mutations are wrapped in undo groups:
docManager.StartUndoGroup()鈫?docManager.ExecuteCmd(cmd)(one or more) 鈫?docManager.EndUndoGroup(). - Components implement
ICmdSubscriber.OnNext(cmd, isUndo)to react to changes (ViewModels subscribe to keep the UI in sync). Non-mutatingNotificationsare also dispatched through the same bus. - The project model (
OpenUtau.Core/Ustx/):UProject鈫?UTrack/UVoicePart鈫?UNote鈫?UPhoneme, plusUExpression,UCurve,USinger. The native file format is.ustx(YAML); seeFormat/USTx.cs.
- API in
OpenUtau.Core/Api/(seeApi/README.mdandPhonemizer.cs). The key method isPhoneme[] Process(Note[] notes, Note? prev, Note? next). - Concrete phonemizers live in
OpenUtau.Plugin.Builtin/. They are discovered by reflection (DocManager.SearchAllPlugins) from the builtin DLL and from user plugin folders 鈥?adding aPhonemizersubclass is enough to register it. - A phonemizer turns notes/lyrics into positioned phonemes; the renderer then turns phonemes into audio.
OpenUtau.Core/Render/Renderers.csis the registry. Each singer type (Classic,Enunu,Vogen,DiffSinger,Voicevox) maps to one or more renderer ids;CreateRenderer(id)instantiates theIRenderer.- All renderers implement
IRenderer(Render/IRenderer.cs):Layout()estimates timing,Render()produces aRenderResult(float samples) perRenderPhrase. Rendering is phrase-based and cached (RenderCache.cs);RenderEngine.csdrives pre-render and playback. - Backends are in their own directories:
Classic/(UTAU resamplers/wavtools),DiffSinger/,Enunu/,Vogen/,Voicevox/, andHifiNeural/. Many use ONNX models viaMicrosoft.ML.OnnxRuntime. - HIFI-NEURA (
HifiNeural/) is the renderer under active development in this fork.HifiNeuralPhraseRendererregisters as renderer idHIFI-NEURA(legacy aliasHIFI-NEURAL-PHRASE) forUSingerType.Classic. The pipeline extracts a mel spectrogram from each phone's oto slice independently (HifiMelExtractor), time-stretches each per phone reusingHifiPhraseFeatureBuilder.WritePhoneMappedSegment(onset/sustain/release split + natural-stretch warp), then concatenates the per-phone mels onto the phrase frame grid with equal-power overlap cross-fades (HifiMelPhraseAssembler, anchored byoto.preutter/overlap). Target F0 comes from the phrase pitch curve (HifiF0Builder), and the mel+F0 run through an ONNX PC-NSF-HiFiGAN vocoder (HifiOnnxVocoder). Output is cached by phrase hash + config (HifiRenderConfig.CacheKey). The old SharpWavtool rough-wav prototype path has been removed from the active code.
OpenUtau.Core/Editing/(BatchEdit) 鈥?macros that mutate notes. Follow the same undo-group + command pattern (seeEditing/README.md). They get a localized name and are discovered by reflection like phonemizers.
- Avalonia + ReactiveUI MVVM.
ViewModels/mirrorViews/.MainWindowViewModelandNotesViewModelare the central editor view models; they subscribe toDocManagerand issueUCommands. Program.csis the entry point;ViewLocatormaps view models to views.
- Both Core and app projects have
<Nullable>enable</Nullable>鈥?respect nullable annotations. - Localized UI strings live in
.resxfiles (OpenUtau/Strings/,OpenUtau/Resources/); translations are managed via Crowdin (crowdin.yml). Use resource keys, not hardcoded display strings, for user-facing text. - Logging uses Serilog (
Log.Information/Warning/Error). .editorconfigdefines formatting (notably 4-space indentation, file-scoped conventions) and is enforced consistently across the codebase.
- GitHub Actions (
.github/workflows/build.yml) isworkflow_dispatchonly: runsdotnet test OpenUtau.Test, then publishes per-RID self-contained builds and packages installers/dmg/AppImage. AppVeyor (appveyor.yml) builds thestablebranch.