LSDJ, short for Little Sound DJ1, is a Gameboy music tracker designed to
actually run on a Gameboy. It works like a charm and is still updated by its
creator, Johan Kotlinski. This blog post won’t talk about this software.
It’s going instead to talk about one of the available tools to extend its functionalities, LSDPatch, or rather my fork, LSDPatch-Redux. But first, I’m going to talk about how LSDJ is organized.
The ins and outs of a cartridge, but mostly the ins.
LSDJ allows both playing with the Gameboy’s Pulse Signal Generators (PSG2 in short) and its WAV channel, the latter in either in a synthetizer mode or a sample mode. The sample mode is using actual PCM samples stored in groups named “kits” which span all the cart space that doesn’t involve code, save or other data. They’re stored this way due to the way the hardware of a Gameboy cartridge is designed, bankswitching in mind.
The Gameboy being only able to address roughly 64KiB of memory, many of the carts were offering a way to increase the available storage by offering the ability to change the memory sector the console is able to reach with its limited memory address. Memory is thus divided in “memory sectors” (also named banks) of 16KiB, and the console is able to read only two ROM sectors at a time, the first one is always mapped to the first 16KiB of the cartrdige where it could change the mapping of the second bank to the other available sections depending on the need of the program.
To do so, the cartrdige bundled a chip specially designed to accept signals coming from the console to determine which sector to export to it. Those are usually named “memory mappers” even though they weren’t only used to this goal. You might have heard of some of the NES’ memory mappers like the VRC6 or the MMC5 due to their audio prowess rather than their capacities in providing the NES more ROM.
What does all of this it have to do with LSDJ? Well, a sample kit fits a memory bank, header data included. They can be smaller, of course, many of the bundled sample kits don’t fill to the rim their respective ROM sectors, but they’ll always be aligned to those 16KiB boundaries. Thus you can have roughly 50 sample kits on LSDJ, provided than Johan or some other file manager don’t use more memory sectors for code or other data.
Also, it’s giving a pretty interesting insight on the way LSDJ is designed. As the cartridge can make only two memory banks public to the console and one is always the same (the first bank), there must be a lot of care on how the software access the data while still having a damned quick routine having to play samples from two different kits, thus banks, possibly in the same time. This feat alone is enough to lose me in the timing complexity required to design a music software like this.
One last note about sectors: the Gameboy also has the ability to access RAM banks, mostly used as extra memory space and the destination for save data. This might be used partly by LSDJ for runtime data, which might explain why if you happen to turn off your console during playback it’s going to be broken on reboot. Fair warning, that’s just suppositions thrown at midnight after a day of work.
LSDPatch is one of the tools helping to develop an ecosystem around LSDJ. With the SAV editor to tweak synth data or easily dump info from your songs, the tool to export a song/ROM combo into ASM code compilable and playable in standlone and LSDPatch alone, you already have a lot to do around LSDJ when it comes to do something else than just compose.
I think LSDPatch’s main goal is to allow the user to customize the sample kits I described with length earlier but also the useable fonts and color palettes (only disponbile when using a system allowing GBC coloration). The editions are done on an in-memory copy of your ROM and writes down the new version when asking it to save, so the whole edition is kinda “atomic”, in a way that there is no half-measures, unless the writeback to disk goes awry3.
Micro-postmortem on a fork decision
LSDPatch is fine by itself, but I originally found that it had a few issues or lacked a few features, like fixing the cartridge’s checksum values for emulators like BGB to not complain at this.
I first tried to only fork to make a few PR, but after a discussion with Johan, a few organization mistakes, a desire to not stay on Java 6 and after a decision which in retrospective sounds more silly than sensible, I decided to simply fork away from the legacy tool.
The software runs on Java and Swing. Unfortunately, I did some Java and Swing,
and I liked it at some point. Yeah. I’m
not sorry. Unfortuntaly (and
really unfortunately this time), it’s kept at Java 6 for legacy compatibility
reasons. It’s not bad in itself, but it impedes a bit on the codestyle. That’s a
very personal point and I still wonder if I didn’t do a mistake back then. I
wanted to bump the target to Java 8, given that one of the most popular video
game ever, Minecraft, ships with its own Java 8 runtime. That simple thing made
me thought it’d not deny a good chunk of the userbase this way, even if I just
hope they just don’t skip on updating Java, even if it has the worst updater
Here’s a small changelog of what changed and what’s planned for now.
- In progress global rework of the sample edition
- Trying to figure a new UI to make edition clearer
- Better sample playback, the samples sounds clearer due in the tool to removal of linear resampling
- Half-speed sample playback.
- Global rework of the font edition
- The sprite grid is fully scalable
- There is support to save/load directly font as PNGs instead of using lsdfnts.
- Planned rework of the palette edition
- WIP Future global UI rework
- Added a way to mass import kits/fonts/palettes
- The file chooser will remember the last used folders
- Adding a main window to quickly toggle the three main edition sub-windows
- Adding a “recent files” field
- Adding as a bonus a kit player
- Adding a window to quick kit/palette/color copies from one cart to another
- Global code rework/cleaning attempt.
- Added command line operations for easier batch process.
- More to come?…
I’d like to center my fork on three specific things : making the UI clearer and scalable, improving the user’s workflow and cleaning the code. There is not a lot to be done in the other situations as the code generally works well, but the UI tends to date a little bit and I’d like to revamp it up. To which point? I don’t know yet, I’m still hesitating about the kind of UI I’d like for the different editors, how they should look like or how the workflow should evolve or stay as it is. I can both break years of habits or just improve the flow on them, or to change them into something I‘d find good that’d not be the opinion of the rest of the userbase. And as of now, I don’t have enough feedback to determine the proper course of action on that specific point. So if you’re reading this blog and would like to send me your two cents on this point, I’d be very happy to hear about that.4
For instance, I’m trying to figure how to redesign the kit editor so it’s less cramped. The old mockup I did ages ago might have good ideas yet I still have issues with how the sample edition looks. I’d like to visually split kit handling and sample handling. I came up with a Midnight Commander-inspired mockup involving two panes and to each their own controllers. One pane on the left for kit handling, reordering, saving/exporting and the other one on the right for sample edition, reordering, etc.
The idea came to me during my “current” attempt at replacing actions in the sample editor while not redoing everything. I didn’t like how everything was on the right pane with poor grouping. Now it has poor grouping, but on the whole window.
Let me explain : the left side has the current kit’s sample list but also most of the sample actions are on the right. The kit list edition is only on the top left of the UI. I was pointed at the disorder a bit after posting a screenshot to some users. Hence the two panes evolution from that. The alternative would also be a vertical layout, but I don’t know if it’d work with so much lists and wide screens on computers
I tried to work on remakes on cross-platform systems. I admit it, I wanted at first it to be a secret project, a suprise, but I have yet to find a system allowing me to work on file and generate sounds manually while not being something as heavy as a game engine. I tried with Haxe and HaxeUI, but the latter lacking a backend offering a cross-platform way to load/write files, I delayed continuing that prototype until I get the motivation to write myself the JS backend for file IO on the web target. I forgot on which HaxeUI backend the prototype worked, but if I remember correctly, it was on Kha. OpenFL’s could have worked if the audio system would accept loading PCM data (for sample playback)… Until I yield and end up makign something JS based, I’ll stick to the Redux version in Java.
Also in long term, I’d like to do a merge between the ROM patching and the RAM patching, to transform LSDPatch and the save manager into a feature complete tool to allow quickly editing a lot of things directly from the same system, but then I wonder if that’s not just pure feature creep and would have been better to just rework the save manager.
In the end, I didn’t expect the amount of time I already spent on it. I thought the upgrade would be more quick. I had to redo things a few time until I got a good feel of the code structure, but I’m sure that it still be improved. Alas, there isn’t yet a way to fully split the GUI code from the ROM management logic, but I hope to be able to progressively do the division. It’d be great if there would be a Java package for LSDJ ROM handling without resorting to LSDPatcher, right?
Anyway, I’ll start this another devlog to keep track of what’s happening in a more verbose way than my changelog and a discussion on a Discord channel. If you need to contact me about it, please tweet at me, that’s probably the best way to hit me up. If it’s for bug reporting or feature requests, the project’s issue tracker is a more fitting place. Anyway, I hope this tool will be useful to you if you happen to make stuff with LSDJ. See you soon.
LSDJ logo trademarked by Johan Kotlinski.