Page 1 of 1

How does Battletoads generate it's PCM drums internally?

Posted: Sun Feb 26, 2017 1:44 pm
by Bregalad
I really wonder, is it considered like a 5th musical channel, or does it generate data based on what is present on the noise channel ? Is it possible to add drums to the regular level songs in order to make them sound better (in the NSF only obviously - not in the game) ?

Re: How does Battletoads generate it's PCM drums internally?

Posted: Sun Feb 26, 2017 3:08 pm
by rainwarrior
I'm pretty sure its a separate "channel" of data, not keyed off of noise. It seemed from the intro/ending music that it could be turned on and off too, since it apparently intentionally cuts out the PCM drums during parts of the intro where there's more animation going on. (I guess they found the "buzz" undesirable otherwise.)

I think it's a poll-based sample loop that just runs from the end of the regular update until the next NMI? (I doesn't appear to use IRQ.) Previous attempts to put it into an NSF used non-NSF-compliant stuff like using IRQs, and tend to work in only one or two very specific players, but since the "Deflemask technique" proved to work in a lot of popular NSF player implementations (including powerpak), I think it would be a really good way to try to do the Battletoads soundtrack in an NSF.

(I'd been meaning to re-rip Battletoads myself using the Deflemask technique for a long while, but it hasn't been high on my to-do list.)

Re: How does Battletoads generate it's PCM drums internally?

Posted: Mon Feb 27, 2017 4:46 am
by Zepper
As far as I know... it requires the $4017 watchdog timer to work properly. Only Nintendulator has such feature. I wonder what's the big idea behind the $4017 register and music playback/control/whatever...

Re: How does Battletoads generate it's PCM drums internally?

Posted: Mon Feb 27, 2017 10:48 am
by rainwarrior
Zepper wrote:As far as I know... it requires the $4017 watchdog timer to work properly. Only Nintendulator has such feature. I wonder what's the big idea behind the $4017 register and music playback/control/whatever...
You're talking about the Battletoads NSF rip that Quietust made for Nintendulator.
http://www.qmtpro.com/~nes/nsf/battletoads_pcm.zip (info)

I believe what this did was have an INIT that never returns, so it just ends in a spinning sample loop. The player detects an INIT that runs for an inordinately long number of cycles, and if it does, it just starts running PLAY as an interruption of the INIT routine. That way whenever it returns from PLAY, it goes back to that sample loop.

If I recall, Blargg's GME also implemented this hack.

I didn't like this "solution" for a few reasons, so I declined to implement it in my NSF player. It's only relevant to this one NSF, which was a one-off experiment. Hardware players like the PowerPak or TNS cart don't support it. (A hardware implementation of this idea would indeed require some kind of interrupt to break out of the non-returning INIT, but you don't need the VS watchdog, you could just use NMI and count frames until the arbitrary "timeout" is reached.)

Re: How does Battletoads generate it's PCM drums internally?

Posted: Mon Feb 27, 2017 12:30 pm
by Dwedit
Wouldn't the best possible solution be for the NSF to return from play after 29780 cycles have passed?

Re: How does Battletoads generate it's PCM drums internally?

Posted: Mon Feb 27, 2017 12:43 pm
by rainwarrior
No, a non-returning PLAY is allowed by the NSF spec and is used for lots of homebrew NSFs (e.g. SuperNSF). Can't remember if it's needed for any commercial game rips, though. There might be "lag frame" PLAY calls that run long and shouldn't be interrupted.

The Deflemask trick (which is widely supported) also relies on a non-returning PLAY.

Re: How does Battletoads generate it's PCM drums internally?

Posted: Mon Feb 27, 2017 12:48 pm
by tepples
I thought a non-returning play routine worked only for an NSF with one song, as hardware players would have no chance to read the controller to navigate to other songs.

Re: How does Battletoads generate it's PCM drums internally?

Posted: Mon Feb 27, 2017 12:54 pm
by rainwarrior
tepples wrote:I thought a non-returning play routine worked only for an NSF with one song, as hardware players would have no chance to read the controller to navigate to other songs.
Hmm, yes, that's a common problem with those. One way to get around this is to poll the controller and return when a button is pressed, but that's very implementation-dependent (and also outside the spec). So... maybe it's not the best way to rip Battletoads either. :S

Anyhow, basically the "return early from INIT" idea solves a problem for exactly one special NSF (quietust's Battletoads rip), and I don't think causes problems for any existing INIT functions which may happen to run too long, but I'm not entirely sure about that. A timeout on PLAY, however, will break hundreds of homebrew NSFs. It kinda depends what you're intending to support, and/or what future NSF rips you're planning to make to rely on it.

There's also the "NSF2" idea, which could add IRQ or other functionality, but nobody's really implemented that yet either.

Actually, maybe I should add an option to NSFPlay to support quietust's Battletoads rip technique...

Re: How does Battletoads generate it's PCM drums internally?

Posted: Mon Feb 27, 2017 2:41 pm
by tepples
Going forward, would it be a good idea to deprecate non-returning init in favor of non-returning play, and then fix the Battletoads rip to return whenever PCM isn't played for greater hardware player compatibility? Or has that already been done?

Re: How does Battletoads generate it's PCM drums internally?

Posted: Mon Feb 27, 2017 3:46 pm
by rainwarrior
tepples wrote:Going forward, would it be a good idea to deprecate non-returning init in favor of non-returning play, and then fix the Battletoads rip to return whenever PCM isn't played for greater hardware player compatibility? Or has that already been done?
Non returning INIT can't be "deprecated", it was a single-use hack that has never been adopted as a standard. Non returning PLAY isn't exactly a substitute for non returning INIT, either. It's just something that's well established and supported in homebrew NSF circles. Non returning INIT is actually a good proposal, but doesn't work with most players.


Since the title track of Battletoads has PCM, if the NSF starts with that track, it'll lock the PowerPak to only playing that track. So, the Deflemask technique could be used as long as the PCM tracks aren't in between the PCM tracks and other tracks, I guess, but you'll only be able to access one of them. I dunno, there's isn't a great way to get more than one PCM track to work. (Polling the controller is effective on PowerPak, and all players I've tried though, but it's dependent on the implementation returning 00000000 with no controller. Then again, the Deflemask technique is already a bit of a hack anyway, since it disables IRQ, etc. so we're already outside the spec here.)

Non-returning INIT is actually a good way to do things, but the arbitrary timeout / watchdog approach feels like a kludgy way to implement it, IMO. The PowerPak NSF player could implement a watchdog IRQ on the INIT routine, perhaps, but I think there are a bunch of problems.

Non-returning INIT was part of the NSF2 proposal. What I think we should really have is an explicit end to the INIT, to tell it when to start doing PLAY. (There was discussion of this re: NSF2.) I'd kind of have a mind to do it as having three function pointers, INIT, PLAY, and IDLE. That way INIT runs, the NSF player sets up a timer IRQ then enters the IDLE loop, then its IRQ (or NMI) starts calling PLAY and checking input whenever it returns. That's the ideal, IMO, but it requires establishment of a new standard, reference implementation, demonstration NSFs, a new PowerPak player implementation, etc. etc. (I have been planning to implement NSF2 in NSFPlay eventually, but emulation accuracy was a higher priority so far, and of course my game project has completely pre-empted it for the time being.)


Anyhow, that's all speculation about the future state of NSF. If you want to make a Battletoads RIP that will run on PowerPak and some popular players, I think the most practical thing to do with current stuff would just be to have multiple NSFs. One for all the non-PCM music. One for each PCM track, using the Deflemask technique. (Or keep it in one NSF and poll the controller.)

...but if you want something that is up to spec and runs on everything that properly implements the spec, we need a new spec and new players. :P

Re: How does Battletoads generate it's PCM drums internally?

Posted: Mon Feb 27, 2017 6:03 pm
by Rahsennor
The reentrancy required for a non-returning INIT is a pain in the ### and I will be dropping support for it next time I touch that part of my NSF player, NSF2 be damned. It's a giant unreadable and error-prone kludge.

Is there any way to make a Battletoads rip whose PLAY return immediately when there's no PCM playing? It's not ideal, but given the choice between laggy controls and timing-variation-distorted sound, I'd pick laggy controls. And it's what I'd do when writing a PCM sound engine.

Re: How does Battletoads generate it's PCM drums internally?

Posted: Tue Feb 28, 2017 9:24 am
by Bregalad
I dunno, there's isn't a great way to get more than one PCM track to work.
Both Battletoads and Battletoads & Double Dragon have (at least) 2 different musical tracks with PCM drums. Battletoads have the title theme and the victory theme, Battletoads & Double Dragon has the title theme and the character select screen theme.

This still doesn't answer how Battletoads handles the PCM drums internally. So far there's a debate about how to implement this in NSF but that's somewhat different. The game seems to somehow freeze itself while playing but resume when not playing, you can see this during the intro when there is dialogue between T-Bird and the Dark Queen, the text appears only when PCM isn't playing. Also in many part (actually most) of the intro PCM playing is disabled.

Trying to log it with FCEU just leads to a huge mess, I cannot even figure out where the data that is written to $4011 comes from. Apparently it's not just plain replaying what's in the ROM and there's some kind of calculations (possibly decompression or some kind of sound synthesis) going on.

Re: How does Battletoads generate it's PCM drums internally?

Posted: Tue Feb 28, 2017 11:31 am
by rainwarrior
Oh, so the samples are compressed in some way? That's interesting.

Just recording the intro's PCM part and looking at the waveforms in an editor, I see a lot of "triangular" straight lines, and in the code I saw a variable timer on the sample output... maybe the format involves straight-line ramp (inc/dec) pieces with variable speed/length?

(Also seems like the overall samples can be played at different pitches too.)

Re: How does Battletoads generate it's PCM drums internally?

Posted: Tue Feb 28, 2017 2:18 pm
by Bregalad
rainwarrior wrote:Oh, so the samples are compressed in some way? That's interesting.
Well, I don't know I just saw that the code arround the $4011 writes weren't a simple load/store/wait loop like you'd expect.

(Also seems like the overall samples can be played at different pitches too.)
I guess this can be easily done just by changing the wait time between writes. If you don't need precise pitch nor constant sample rate this is simple to achieve.

Re: How does Battletoads generate it's PCM drums internally?

Posted: Sun Mar 19, 2017 2:24 pm
by Bregalad
Looking more in detail at code once more, I'm pretty sure it does not play samples at all - instead it simply synthesize sounds with matematical formulas, made of additions substractions, logical operations and shifts.