The focal point should be sound.inc and sound.asm. One defines macros, the variables in zero page and bss that the MML driver requires, and the other imports the MML driver bank itself in all of it's glory. Since the MML driver disassembly is pretty damn good and the driver itself is very self contained, it's easy to import it to any hucard project with minimal modifications:
1. on lines 214, 260 comment out the .org statements. Write on line 214 ".zp" to indicate we're reserving zero page space, but without being any specific about it.
2. sound.inc imports 3 other header files, common.inc, main.inc and sub.inc. On those three files we also define reserved memory on RAM. Swap the .org statements with just ".bss", or preserve the .org by surrounding it with an ".if(CDROM)" statement.
3. comment out the .bank statement at lines 24 and 166, move the whole function psg_driver to before line 121 (".bank SOUND_BANK...")
4. swap line 121 with
Code: Select all
.bank BANK(*) + 1 .page 6
Code: Select all
.bank BANK(*) - 1
(the new banking is done to my personal preference, but dummying out the .org statements should be smart for any project, really.)
The MML driver comes from a (very good) disassembly of the system card, and because of the fact that sometimes CD projects will want to use some squirrel files WITH the BIOS PSG player, the driver has very rigid memory/ROM placement details (and HuC probably does that too in order to simplify things); but the point of a disassembly is to be able to reassemble it for our own benefit, and our modifications allow MML stuff to sit anywhere. To actually USE the driver is really simple. Our modified sound.asm allows us to import the critical functions psg_bios and psg_driver that is called in the interrupts, AND it uses the next bank on the ROM for the actual PSG driver (that really needs a bank for itself).
1. ".include sound.inc" on your main program file
2. ".include sound.asm" on bank 0
3. ".bank(psgOn) + 1" on the "next bank" so you can skip the PSG Driver bank and not overwrite any of it!!!
4. On your IRQ1 handler, add the macro call __sound_vsync |OR| On your TIMER handler, add the macro call __sound_timer
5. Initialize the PSG Driver with commands 0 and 2 to psg_bios, including choosing TIMER/IRQ1, Main/Subtrack enable and default timebase (see Hu7 docs).
To include actual MML songs converted with mml2pce on your game, there's nothing special you need to do, just include the .asm it generates anywhere in your project, in a bank that sits in .page 4 ($8000) which is how the PSG driver maps song data in during playback. The also generated SngInit.c lets the PSG driver know where our music/instruments/envelopes are, but thankfully it's a trivial conversion to pure ASM, just leave out the fixed .bank include it adds to the .c file.
Yeah the text ended up being a tad bit long but it's really nothing complicated at all. For your benefit I've released into github a simple game in ASM that does what I just described, just don't focus on the bad rushed code for the game . See main.asm to see how I include sound.asm/sound.inc into the project and the macro calls. I've also included ONLY the files I modified from squirrel so you can inspect the changes to them too, if my description failed to be clear.
EDIT: forgot link, doh. https://github.com/AleffCorrea/PCEnginePong