Building a cross-platform generative-music SDK

Yingchen Liu
How I led Aimi’s shared playback architecture, founded the Android team and improved startup performance while keeping quality measurable.
- C++
- TypeScript
- Kotlin & Media3

01
A generative-music engine produces a changing performance, not a playlist
Aimi Player is a generative-music app. It creates an evolving performance from musical material and product rules, rather than playing a fixed playlist.
The same underlying musical state must behave consistently when used by different products, while each platform still controls audio focus, background playback, interruptions, caching and its native interface.
That creates three architectural layers. A portable C++ engine owns the generative behaviour; a product-facing TypeScript SDK exposes a stable integration boundary; and native clients such as Android use Kotlin and Media3 for platform lifecycle and playback. Sharing the engine avoids rewriting the musical rules, but sharing the entire player would make every platform less native.
02
The problem
Generative music is not a playlist of fixed files. Playback has to coordinate an engine that can assemble and evolve music in real time, a product SDK used by multiple surfaces, and native audio behaviour that users expect to continue through interruptions, backgrounding and device changes.
The engineering challenge was to share the musical product logic without reducing every platform to the lowest common denominator.
03
Outcomes that travelled with the architecture
Outcome snapshot
The available verified portfolio evidence covers these product outcomes; this article deliberately avoids inventing unavailable commit-level detail.
52%
faster startup
Reduced time before the music experience became useful.
96%
test coverage
Made cross-platform change safer and more reviewable.
3 layers
shared product architecture
C++ engine, TypeScript SDK and native Android playback.
How I implemented it
I led development of the cross-platform SDK and founded the Android team. The app used Kotlin, Jetpack Compose and Media3 around the shared engine, while web and service integrations used the TypeScript layer. Build and delivery work ran through AWS, Docker, Terraform and GitHub Actions so the same architecture could be exercised consistently from development to release.
Startup became an explicit performance path rather than a side effect of initialising every dependency. Test-driven development and clearer module boundaries raised coverage to 96%, giving the team confidence to improve that path without destabilising playback.
04
The decision
I led a layered architecture: a C++ core for portable engine behaviour, a TypeScript and Node.js SDK for product integration, and a native Kotlin/Media3 Android application for lifecycle and playback. The boundary let each layer be tested independently while keeping one product model.
The decisions that shaped the system
- 01
Keep the engine portable
Core generative behaviour belongs in C++ so the musical product model can travel without copying it into every client.
- 02
Use a product-facing SDK boundary
TypeScript and Node.js expose the shared engine to web and service integrations while keeping platform code outside the core.
- 03
Keep playback native
Kotlin and Media3 own Android lifecycle, audio focus, background playback and interruption behaviour around the shared engine.
05
What improved
Startup time improved by 52%, and the shared engine could serve native and web-facing product surfaces without duplicating the core generative logic. The Android team gained a platform-appropriate playback stack and a testable integration boundary.
06
What I learned
A cross-platform SDK succeeds when it makes the shared product idea portable while leaving lifecycle and user experience native. Performance and testability are architecture outcomes, not final polishing steps.
Takeaways
- Share the engine, not the platform lifecycle.
- Treat startup as a measured product journey.
- Use testable boundaries to make cross-platform work safer.