Gamecube .HPS music by nifanatic at 7:55 PM EDT on September 5, 2009
Been trying to do some GCN/Smash Bros. Melee music editing, but I can't seem to nail .hps format. Would anyone happen to know how it's possible to convert, say, WAV files into working HPS files that can run in-game?
Oh, and a GC iso program that allows larger files to replace smaller files would be nice, like with Wii Scrubber. Otherwise the music possibilities are very limited.
I don't know of any existing tools for creating HPS, but it shouldn't be hard to make one. It'd require DSP format input, though, as with dkdsp or revb. This does not mean that I'm working on such a thing.
Do you have written documentation on the HALPST format, hcs? I was able to get a cached version of the DSP information from a "wiki" off of the sourceforge page, but now everything with a url pointing to this wiki sends me to the sourceforge mainpage. Do you have the original documentation? I'm interested in trying to make a WAV -> HPS converter.
HPS (HALPST) format info by hcs at 9:11 PM EDT on September 7, 2009
I've still got a dump of the wiki, looks like I never put up anything interesting about HALPST. vgmstream itself is probably the best documentation around, here's a rundown of what I see now:
(integers are big endian) 0x00-0x07: " HALPST\0" // magic 0x08-0x0B: sample rate 0x0C-0x0F: channel count
block structure (blocks start at 0x80): 0x00-0x03: block size (all channels) 0x04-0x07: last nibble in block to play? 0x08-0x0b: next block offset (looping implemented this way!) 0x0C-0x13: left channel decode state 0x14-0x1B: right channel decode state 0x1C-0x1F: 0? padding? Then the left channel starts, and the right channel starts halfway through the block.
per block per channel initial decode state: 0x00-0x01: initial P/S 0x02-0x03: initial hist1? 0x04-0x05: initial hist2? 0x06-0x07: 0? gain? padding?
Oh, and I should note that nonlooping tracks are indicated by a 0xFFFFFFFF for the last "next block". Also mono HPSes are possible (and if you don't have a way of inserting larger files you might try this to save space), but I don't recall what game had them to check against this info.
edited 9:25 PM EDT September 7, 2009
edited 9:41 PM EDT September 7, 2009
So after looking at it for a little I've decided to go ahead and make a revb-type utility for this format. I'll post when it's done.
Thanks for all that info. It's pretty much what I gathered by looking through vgmstream. My issue is understanding the bitwise operations when decoding the blocks. :/ A revb, halpst style, would be absolutely great. I'd be very impressed..and grateful. Keep it up.
I still don't understand the hps spec.....it's a bit weird thanks to HAL... anyway, here's my attempt at hps making by hand: hpstest4.hps edit: fixed nibble count
Good show, bxaimc... But the only unfortunate thing is, won't be able to test than in Melee due to how massive the size is. I can only replace themes that are of equal to less KB size as the song I'm wanting to replace. Nothing comes close to 10MB, last I checked. If you could find a way of shrinking... that'd be great.
In any case, with voice replacements being worked on as well, having something to work with HPS files would be a godsend... Appreciate you taking up making something for it, hcs. :)
Under the "block info" section from an earlier post by hcs, there's this: 0x0C-0x13: left channel decode state 0x14-0x1B: right channel decode state
How are the decode states determined for HPS files given the DSP that it's playing for each block? Not changing them when inserting custom DSPs doesn't seem to affect the performance of the new HPS, but I'd like to be as accurate as possible.
I don't know if those states are actually used by the decoder, but the test program I wrote confirms that those are the accurate values at the start of each block. The state breaks down as follows: 0-1: initial p/s (this is simply the first byte of the channel) 2-3: initial history 1 4-5: initial history 2 6-7: 0?
The histories are computed by decoding the previous block and seeing what the last two samples were.
Note: I can post what code I have now if you're interested, but note that it's only in the "check existing .hps" stage.
Cool, I was just wondering how it affected the HPS while decoding. I understand the histories, etc.
I wrote a program that runs dspadpcm and inserts the DSPs created into a temp.hps file. I found out at first that I had made an error with those decoder states (I just didn't include them in the block headers), so I wondered what use they had.
I'd be interested in the code. I think I could learn a few things.
hcs says: "The histories are computed by decoding the previous block and seeing what the last two samples were."
Can you clear up how this is done? I'd like to perfect this HPS substitution program I have, which currently skips over the decoder states without changing them. The audio works, but there are pops and cracks at some points in the music when it's played ingame.
When I read this, I thought you meant that the last 8 bytes from each block were repeated as the decoder states (histories), but when I checked some of the original HPS files from the game, I couldn't find any evidence of that. There seems to be some calculation done to figure these values out.
Take a look at the loop at line 459, that's what does the decoding. Then the final values at info[c].state.hist1 and hist2 should be in the header of the next block (though this does not hold for the loop, apparently).
Thanks. So the decode_dsp_nowhere() will crank out the hist1 and hist2 for the block. I didn't see that at first. Thank you. May I use this code (with a few changes) in my program?
Hey hcs, I know this is an old topic but do you mind if I take hcshps and use it for pretty much the same exact reason that god was using it? If I get it to work I would of course give you credit for the parts that you did and can show you the source.
This thread just reminded me, I need to bug soneek to release whatever he's using to convert between Nintendo dsp formats on SCM in some usable format. Unless he's already done that, and I'm just way behind (but I doubt it).
Alright.. so originally, I was running into an issue with Nintendont's audio using custom HPS files and thought that the issue was due to incorrect decoder states in the block headers of my custom HPS files. I created an option in hcshps that fixed (or at least it seems to fix) those decoder states in block headers given an input HPS file, but files that I patched using this new option still didn't fix the audio issue that I was running into with Nintendont. I figured out that it had to do with block size. I made a post about it here:
Good to know about the block size, it's scary how tightly tuned these drivers can be.
Re: looping, iirc the original .HPS files use smaller blocks at the loop point so that they can loop more accurately, so you can probably get away with it like that if you want easier looping.