PKsinew Devlog # 8: Embedding mGBA and Switching Between Game and Sinew
Embedding mGBA, unifying controls, and making Sinew feel like a system

By this point, Sinew could do a lot — but the experience still felt fractured.
Launching games externally meant context switching:
Alt-tabbing
Separate controller configs
No clean way to jump between the game and Sinew
I wanted a fast, console-like way to switch between Sinew and whatever game was running — something closer to a Home button than a desktop workflow.
The External mGBA Problem
Using external mGBA, this is technically possible via its scripting API.
The idea would be:
Run mGBA as a separate process
Use its scripting hooks
Spin up a Node.js server
Listen for controller button combinations
Send commands back to mGBA
It works — but it’s messy.
It adds:
Extra services
Network plumbing
More failure points
And it didn’t feel right for what Sinew was becoming.
Thinking Like RetroArch
That’s when I started thinking about how RetroArch does things.
RetroArch embeds emulators directly using libretro cores, which expose:
Video frame buffers
Audio buffers
Input callbacks
So I wondered:
What if I embed the mGBA libretro core directly inside Sinew?
In theory, Python could do this.
In practice… it was rough.
First Attempts (and Shelving It)
I’d played around with this earlier while I was out of Claude tokens, using ChatGPT.
I managed to:
Get the frame buffer rendering into a Pygame surface after some trial and error
Get input mostly working
Get audio, but it was extremely choppy
Break save handling completely
It worked, but it didn’t feel stable or shippable — so I shelved it.
Claude to the Rescue (Again)
Later on, I dropped the same code into Claude and asked it to take a look.
Within minutes:
The audio bitrate was corrected
Audio became silky smooth immediately
Save handling was fixed
That was all I needed.
At that point, embedding the emulator directly into Sinew became viable.
Embedding mGBA Into Sinew
Once embedded, everything started to fall into place:
The emulator now uses Sinew’s ROM paths and save paths
A unified button mapper controls both:
Sinew UI
The running game

I wired in a Start + Select combo that instantly switches between:
The game
The Sinew menu
From there, I added guardrails:
You can’t launch another game while one is running
Sinew offers:
Return to game
Stop game
The button combo works globally

At this point, Sinew finally felt cohesive.
Catching Up to Today
This devlog is now starting to catch up to the present.
Today, I added:
An option to change the button combo
Support for using a single custom “Home” button
This matters because:
GBA doesn’t have many buttons
Many controllers do have Home buttons
Some only have just enough buttons
Flexibility here was important.
The Bug You Only Find by Playing
After all that, I did the sensible thing.
I kicked back, loaded up FireRed, and relaxed before heading to a Christmas party.
Five minutes in — the audio died.
Turns out the issue was subtle:
The emulator was producing audio faster than it was being consumed
Unused audio chunks were queuing up
Once the queue filled, audio playback crashed
The fix was simple but necessary:
Keep a small audio buffer
If more than a few chunks are waiting, discard the oldest unused audio data
In other words:
Better to drop stale audio than let it pile up and kill sound entirely.
Problem solved.
Where This Leaves Sinew
At this point, Sinew can:
Launch games internally
Switch instantly between game and UI
Share controller mappings across both
Enforce safe rules around save access
Recover gracefully from real-world edge cases
This is the point where Sinew stopped feeling like a tool and started feeling like a system.
Next Up
Settings
Themes
Mass Pokémon storage
And then… polishing.






