Modernizing MML for 2022 (2) migrating from C# to Kotlin and extending capabilities
part 1 / part 2 / part 3 / part 4 / part 5
(This chapter has no audio topics, skip to (3) if you want.)
By the time I wanted to bring it back and use it again, it became almost impossible to continue C# development on Linux due to lack of well supported IDE (which was caused by the Visual Studio leadership that recently exposed quite infamous problem around Hot Reloading). I ended up to switch to Kotlin, named the new project as ktmidi, as I posted here last time.
As an after story, the migration was quite successful and I could get back my productivity. The new MML compiler mugene-ng now supports vscode-extension natively (thanks to Kotlin/JS) without resorting to external compiler processes, and I look to extend it to Web browsers (that needs more investigation on Kotlin-JSIR). The virtual MIDI keyboard app kmmk makes use of Jetpack Compose and Compose for Desktop so that it runs on both desktop and Android without problem, and potentially for Web, with preliminary MIDI 2.0 support.
The last thing I missed though was the MML compiler experiment I mentioned earlier - MML for audio plugins using Tracktion Engine. After some break from ktmidi hackings, I started working on the final migration - augene-ng.
Technical challenges on .NET -> Kotlin migration
It is not an essential topic here but I would list up a couple of migration problems and solutions.
(1) The MML parser implementation in the old repo was using C# port of jay, which is an LALR(1) parser. The parser style is too traditional and it was often my desire to rewrite from scratch, but after exploring choices in Kotlin Multiplatform, I ended up to just switch to ANTLR and use antlr-kotlin, fixing some issues I encountered in it (already merged to master). I had various issues on building my project but after splitting modules into separate projects they are all gone (except that it's super annoying as an ex .NET developer and Kotiln Gradle plugin seriously needs some remedy IMHO though).
(2) The old .NET version used a lot of reflection tricks to implement my own XML serializer (which was without resorting to existing solutions which usually bring in minor glitches). I thought kotlin.reflect
just works like java.lang.reflect
, but turned out that it is useful only on Kotlin/JVM. KType
on Multiplatform has no access to fields, properties and methods.
After some thoughts I ended up to use KSP (Kotlin Symbol Processor) (not to be confused with Kontakt Script Processor in our domain) to generate Kotlin sources of meta type information from my own Kotlin source code for the music data model at compile time, and kept large chunk of the existing code logic as is. Probably I should write a separate post on how I achieve that, but it's going too off topic today.
(3) There was no viable XmlReader
and XmlWriter
alternatives in Kotlin Multiplatform. XML seems regarded as obsolete technology and people only care about JSON. However XML is still actively used in our domain and good for readability with clear structure. Tracktion uses it as the music file format and I needed a solid XML reader and writer implementation. There was a kotlinx-serialization extension that tried to support XML, but lacked Kotlin/Native support and I'm quite unsure if its strategy to have different implementation per platform is viable. I ended up to write my own XML reader and writer from scratch (somewhat hacky but works enough). I also used XLinq too, but it was a one-day hack to implement a Kotlin alternative.
They are packaged as atsushieno/missingdot and published as a Maven artifact for those who want to similarly migrate from C#/.NET to Kotlin.
(4) GUI. I was using mono/xwt as the cross-platform desktop solution which gave me the closest-to-native experience at the moment. It had to be rewritten for completely different UI framework anyways, so I just picked up the emerging (Jetpack) Compose for Desktop this time.
My concern was rather to redesign the code structure to have an appropriate music compiler part from the UI part (it was such a small project that I didn't really care), and I haven't really paid attention to my UI bits (even now). I have some complaints (e.g. lack of native file dialog), but so far it kinda works.