Music as PCM for Sonic 1?

Discussion in 'Discussion & Q&A' started by realwushy, May 9, 2022.

  1. realwushy

    realwushy Newcomer Trialist

    Apr 25, 2022
    Is there a way to make PCM music play instead of FM or SMPS? I know RHS did this when you get game over in Sonic 2 Recreation Part 1, but that was Sonic 2. Is there a way to do it in Sonic 1, if it even is possible? Feedback would help!
  2. Dark Shamil Khan

    Dark Shamil Khan TASer lol Member

    Nov 7, 2021
  3. Inferno

    Inferno Rom Hacker Member

    Oct 27, 2015
    Sky Base Zone, South Island
    If Sonic 2 can do it, so can Sonic 1.
    Keep in mind that your only limits are the hardware's; otherwise, you just change the code to work with you.
    MegaPCM is actually ok for this purpose.
    Crimson Neo likes this.
  4. ralakimus

    ralakimus amazingly still alive Member

    Aug 26, 2013
    There are some drawbacks to using PCM for music. Sample data can really fill up ROM space if you are not careful. There's also the issue of playback quality. There's a number of factors that could go into it, besides the quality of the sample itself.

    PCM playback is usually done on the Z80 CPU on the Genesis. Sample data has to be manually streamed to the YM2612's DAC channel, and the 68000 CPU would not exactly be the best candidate for handling this, as that also has to handle game logic and all that stuff, so the job is typically given to the Z80. The Z80 is also sometimes tasked to handle sequence data for music and sound effects, but it's much more feasible to do that, while also managing PCM playback at the same time (this is also a factor that can affect playback quality, depending on how the code is set up). On board is 8 KiB of RAM in which Z80 code and data is loaded into. What Sonic 1 does with the Z80 in its stock driver is store all the drum samples in RAM, stored in a 4-bit format, which gets decoded during playback. It got the job done well enough for Sonic 1, but for ROM hacks that want to expand on that, it's just not enough. The Z80 does actually have a way to access 68000 memory, and that's through a 32 KiB window, in which the Z80 can view a bank of 68000 memory, including cartridge data. Mega PCM is a PCM playback driver that takes advantage of this, so it streams sample data directly from the cartridge, and even supports both 4-bit and regular 8-bit PCM formats.

    However, there are some factors to be aware of when doing PCM playback on the Z80. For one, the Z80 is often halted for a little bit every frame. Halts in the PCM playback code are more or less what really kill the playback quality. The Z80 needs to be halted for the 68000 to access the Z80's bus/memory, and according to the hardware manual, it also needs to be stopped if you are handling controller reading and VDP DMAs, or else issues will arise (I think it depends on the cartridge hardware, too, though?). You might have seen the part in the Mega PCM thread where it talks about improving playback quality. Unfortunately, the way it achieves that is by moving all the Z80 stops away from the controller reading and VDP DMA code to only where the SMPS driver on the 68000 side accesses Z80 memory to set flags and stuff. In theory, this would be preferable, and works okay in emulation, but it also raises the said risk of issues on actual hardware (To be fair, though, I'm not quite too sure about this fully, if someone who's experienced it wants to step forward, please do). Even then, "optimizing" the Z80 stops alone won't actually make playback sound good on hardware, as there's one other key thing to take note of.

    When the Z80 accesses 68000 memory through the bank, it basically has to halt the 68000 for a bit to retrieve data from it. The process that it does this is known as "cycle stealing". For it to work, the 68000 needs to be readily available for the Z80. If the 68000 is unavailable, then the Z80 is halted until it can get the data. The most common way that the 68000 is made unavailable to the Z80 is via VDP DMAs. This is why, even if you don't stop the Z80 for VDP DMAs to be done, your playback will not sound great on hardware. The VDP basically gains access to the 68000's memory so that it can copy data from it to its memory during a DMA, and thus it stops the 68000 until its done. As a result, the 68000 also cannot respond to the Z80 wanting data, so the Z80 has to wait if it needs to do so. You can attempt to mitigate this, though. The "easier" method would just to not use VDP DMAs at all. Manually copying data to the VDP is much slower than allowing the VDP to directly access 68000 memory to do a fast copy, for one thing, so performance on the 68000 can tank if you're not careful. Really depends on how you go about it. There's also some kind of issue with the VDP's FIFO with it halting the 68000 for a little bit if it's too full for data to be written to it (or empty if there's a read), but I don't really remember if manual mass copying is fast enough to cause that to happen (I do know it's definitely an issue for VDP DMA to VRAM).

    What Dual PCM does is buffer sample data into an internal buffer in Z80 RAM ahead of time. During normal circumstances, it basically just streams directly from the cartridge, but it can be set into a mode where it will read from its internal buffer instead, keeping the Z80 from accessing 68000 memory, keeping the playback smooth. Of course, if the 68000 is halted for too long, and the buffer is played back fully, then it'll basically just stop until things are available again, but there's nothing that can really be done to help that, as far as I know. The "Flex Ed" also has you queue up YM2612 register writes into another buffer in Z80 memory. I'm not too sure about the full details at the moment, but I do know that the YM2612 is actually on the Z80 bus, and it also allows the driver itself to track how register writes are handled (for PCM playback to continuously work, if I recall, the register ID has to be set to the DAC write ID).

    Mega PCM is nice and simple enough to work with, but you'll have to take into account these issues if you don't want the playback to sound awful on real hardware. In general, I personally find it to be better suited for easy basic sample playback in sequenced music. Dual PCM can definitely seem like a chore to figure out due to its complexity, but for actual music playback, it's the better choice. The Flex Ed version's sample playback is hardcoded to ~14 kHz, but it's really not that bad of a sample rate if played back smoothly, and comes with a good set of features, like volume control, smooth pitch control, and even reverse playback, on top of the buffering stuff. The original version is less featureful, but it still has the buffering thing, and plays back at a higher sample rate (at around ~20 kHz).

    You still have to keep in mind ROM space limitations, though.

    By the way, Sonic 2 Recreation uses a port of Sonic 1's version of SMPS.