A from-scratch port of the Python ffx_core engine to C#, targeting
.NET Framework 4.8 specifically for real Windows 7 compatibility —
see the repo's earlier history for why: Python 3.9+, Qt6 (PySide6), and
even PySide2's available wheel range all independently stopped supporting
Win7, and chasing each one individually stopped being productive.
I could not compile or run this C# code myself — this sandbox has no .NET SDK installed and no way to install one (network access here is locked to a handful of package registries, not Microsoft's). Every line was written by careful manual translation from the Python version that was fully tested against your real preset files across this whole project, but the C# port itself has not been executed by anyone yet.
.github/workflows/test.yml is set up to build and run the full test
suite (a port of every meaningful test from tests/test_riff.py and
tests/test_pipeline.py, including a real-file round-trip using the same
sample_1.ffx fixture) on windows-latest the moment you push this. That
CI run is the actual first real test of this code — please check it
before trusting the logic, the same discipline the Python version went
through before any of it got called "confirmed."
If it fails, the most likely culprits, roughly in order of likelihood:
- A typo or off-by-one in the manual translation (most likely — this is hand-ported, not machine-translated)
System.Text.Jsonversion pin needing adjustment for net48 compat- Something about the
<None Include>linked-file paths forplugin_table.json/ the.ffxfixture not resolving the way I expect acrossdotnet build's output structure
None of these would be surprising for a first-pass port — flag whatever the CI output shows and I'll fix it directly rather than guess further.
FfxTool.Core/ # port of ffx_core — RiffNode.cs, Pipeline.cs, PluginLookup.cs
FfxTool.Core.Tests/ # xUnit port of test_riff.py / test_pipeline.py (incl. fixtures/sample_1.ffx)
FfxTool.Gui/ # WinForms GUI — MainForm, ListerTab, ProfileTab, ConvertTab, SettingsTab + MD3 theme
data/plugin_table.json # shared verbatim — copied to output via <None Include Link> (Core + Gui)
.github/workflows/test.yml # dotnet build + test on windows-latest (Core + Gui)
.github/workflows/build.yml # Release zip of FfxTool.Gui.exe + dependencies + data/plugin_table.json
FfxTool.sln includes all three projects (Core, Core.Tests, Gui) so a single dotnet build FfxTool.sln builds the entire repo. Each csproj links ../data/plugin_table.json with CopyToOutputDirectory=PreserveNewest; Core.Tests additionally links fixtures/*.ffx.
Every hard-won detail from RESEARCH_NOTES.md carried over as-is:
fnamchunks get padded to a fixed 48 bytes;tdsn/pdnmstay variable-length — these are NOT the same treatment (this distinction was Mistake #3 in the original derivation; getting it wrong crashes AE).- Effect removal matches
sspcblocks totdspentries by position, not name, and always renumberstdixafterward. - Keyframe (
lhd3/ldat) and third-party plugin blob data is never touched by any pipeline step, andPipeline.Verify()checks this holds after every conversion — same verification discipline as the Python version, not weakened for the port.
dotnet restore FfxTool.sln
dotnet build FfxTool.sln --configuration Release
dotnet test FfxTool.sln --configuration Release
# GUI: FfxTool.Gui\bin\Release\net48\FfxTool.Gui.exe (+ data\plugin_table.json alongside it)