SPC File Format

Strictly for discussing ZSNES development and for submitting code. You can also join us on IRC at irc.libera.chat in #zsnes.
Please, no requests here.

Moderator: ZSNES Mods

Nach
ZSNES Developer
ZSNES Developer
Posts: 3904
Joined: Tue Jul 27, 2004 10:54 pm
Location: Solar powered park bench
Contact:

SPC File Format

Post by Nach »

Okay, so I've been porting this code in ZSNES.
I noticed in the process conflicting comments, and then code which does different than the comments (either of them), and in fact stuff which looked like off by one errors in a few places.

So after finally working it all out, I've come up with this:

Code: Select all

00000h-00020h - File Header : SNES-SPC700 Sound File Data v0.00 (33 bytes)
00021h-00023h - 0x1a,0x1a,0x1a (3 bytes)
00024h        - 10 (1 byte)
00025h        - PC Register value (1 Word)
00027h        - A Register Value (1 byte)
00028h        - X Register Value (1 byte)
00029h        - Y Register Value (1 byte)
0002Ah        - Status Flags Value (1 byte)
0002Bh        - Stack Register Value (1 byte)
0002Ch-0002Dh - Reserved (1 byte)
0002Eh-0004Dh - SubTitle/Song Name (32 bytes)
0004Eh-0006Dh - Title of Game (32 bytes)
0006Eh-0007Dh - Name of Dumper (32 bytes)
0007Eh-0009Dh - Comments (32 bytes)
0009Eh-000A1h - Date the SPC was Dumped (4 bytes)
000A2h-000A8h - Reserved (6 bytes)
000A9h-000ACh - Length of SPC in seconds (4 bytes)
000ADh-000AFh - Fade out length in milliseconds (3 bytes)
000B0h-000CFh - Author of Song (32 bytes)
000D0h        - Default Channel Disables (0 = enable, 1 = disable) (1 byte)
000D1h        - Emulator used to dump .spc file (1 byte)
                (0 = UNKNOWN, 1 = ZSNES, 2 = SNES9X)
                (Note : Contact the authors if you're an snes emu author with
                 an .spc capture in order to assign you a number)
000D2h-000FFh - Reserved (46 bytes)
00100h-100FFh - SPCRam (64 KB)
10100h-101FFh - DSPRam (256 bytes)
Any errors? Anyone know anything different? This okay?
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
creaothceann
Seen it all
Posts: 2302
Joined: Mon Jan 03, 2005 5:04 pm
Location: Germany
Contact:

Post by creaothceann »

This is the most recent description (minus the emulators list and some extended ID666 tags), afaik:
http://www.romhacking.net/docs/SPCFormat_031.txt

I think the offset changes between text format and binary format are real; at least SNESAmp and vSNES use these differences to guess the actual format. :? I think I tested that, but my memory is a bit fuzzy.

There were more emulators and ID666 tags defined; see the source of SNESAmp or vSNES for a list: http://alpha-ii.com/Source/index.html
I've seen SPC files with unknown ID666 tags though.

If ZSNES can output SPC files in binary format then it should be fine.
vSNES | Delphi 10 BPLs
bsnes launcher with recent files list
Nach
ZSNES Developer
ZSNES Developer
Posts: 3904
Joined: Tue Jul 27, 2004 10:54 pm
Location: Solar powered park bench
Contact:

Post by Nach »

Your doc has:

Code: Select all

000A2h     7 unused
000A9h     3 Number of seconds to play song before fading out
000ACh     4 Length of fade in milliseconds
Which doesn't exactly match my data...

Okay, I have an off by 1, it is 7 unused.
However I have the length of song and fade reversed.

Which is correct? I would think my spec is correct, since doesn't it make more sense for the song length do be larger than the fade even if song length is already *1000?

And I know nothing of this text format.
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
creaothceann
Seen it all
Posts: 2302
Joined: Mon Jan 03, 2005 5:04 pm
Location: Germany
Contact:

Post by creaothceann »

I just copied that, I don't know much about it, sorry. If there was any problem I used the SNESAmp code as reference. :?
vSNES | Delphi 10 BPLs
bsnes launcher with recent files list
byuu

Post by byuu »

Speaking of which, are we ever going to fix the problems with the spec?

Specifically, regs $f0-$ff aren't saved anywhere (unless you consider those to be in true SPCRAM $00f0-$00ff), the IPLROM is needlessly duplicated in every file where the extended RAM should be, and only the newest spec even has the extram saved to the top of the extra 128 bytes because the original spec didn't even realize there weren't 256 DSP regs, no timer information is stored, and I'm sure I could think of more given more time.
Nach
ZSNES Developer
ZSNES Developer
Posts: 3904
Joined: Tue Jul 27, 2004 10:54 pm
Location: Solar powered park bench
Contact:

Post by Nach »

byuu wrote: Specifically, regs $f0-$ff aren't saved anywhere (unless you consider those to be in true SPCRAM $00f0-$00ff), the IPLROM is needlessly duplicated in every file where the extended RAM should be, and only the newest spec even has the extram saved to the top of the extra 128 bytes because the original spec didn't even realize there weren't 256 DSP regs, no timer information is stored, and I'm sure I could think of more given more time.
Um...
Can you elaborate? I'm not sure what you're talking about.

Regarding what is saved:

Code: Select all

      fwrite(ssdatst, 1, sizeof(ssdatst), fp);
      fwrite(SPCRAM, 1, 65536, fp); //00100h-100FFh - SPCRam
      fwrite(DSPMem, 1, 192, fp);   //10100h-101FFh - DSPRam
      fwrite(spcextraram, 1, 64, fp); //Seems DSPRam is split in two, but I don't get what's going on here
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
byuu

Post by byuu »

There are 128 regs for DSP. The original SPC format authors figured there were 256. They also ignored the EXTRAM and always wrote out the IPLROM at the end of SPCRAM. So someone decided to half-ass extend the format by sticking the EXTRAM into the top of the DSP regs that are unused.
-- Don't get me wrong, I appreciate the backwards compatibility, but I'd rather fix the problems right than build on top of a poor initial design.

Of course, the EXTRAM should've just been inserted in the linear 64k RAM section, the IPLROM should've been omitted entirely since it's static, the DSP regs should've been halved, the SPC700 registers $f0-$ff should've been saved (again unless they're in $00f0-$00ff SPCRAM), and the SPC700 3x timers should've been saved.

There's also quite a few internal DSP registers that are ignored, but you'd get pretty emulator-dependant by including those :(
Nach
ZSNES Developer
ZSNES Developer
Posts: 3904
Joined: Tue Jul 27, 2004 10:54 pm
Location: Solar powered park bench
Contact:

Post by Nach »

I don't know who you're refering to. It's _Demo_'s format, he invented it, he updated it. Anything else out there is whatever.

From what I see the current code is doing and from what I understand from what you're saying, we're missing some timers. Is that it?
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
byuu

Post by byuu »

It was great for the time. We should reorder it to do the things I was mentioning, but I imagine breaking compatibility would be out of the question, sadly.

As for timers, I'm betting the current format is exporting the SPC regs to SPCRAM $f0-$ff, and then restarting the timers from zero at the point of SPC load. Not -awful-, it'd probably cause a little glitchiness of the sound right at the start in some sensitive games with no pause.

And there's lots of internal DSP variables that are discarded for the snapshot. You could, for example, be in the middle of playing a BRR sample when the SPC file is dumped.

But, for what it is, a simplified format that plays most things "good enough", it's a great idea.
Nach
ZSNES Developer
ZSNES Developer
Posts: 3904
Joined: Tue Jul 27, 2004 10:54 pm
Location: Solar powered park bench
Contact:

Post by Nach »

byuu wrote:It was great for the time. We should reorder it to do the things I was mentioning, but I imagine breaking compatibility would be out of the question, sadly.
I still don't know what you're talking about.
byuu wrote: And there's lots of internal DSP variables that are discarded for the snapshot. You could, for example, be in the middle of playing a BRR sample when the SPC file is dumped.
You're supposed to dump the SPC prior to a new BGM being loaded. ZSNES searches for the next one, and gets you the whole thing. It just means though you need proper human timing to get the audio.
byuu wrote: But, for what it is, a simplified format that plays most things "good enough", it's a great idea.
It seems to play everything but streaming audio. And AFAIK, it's the only format that you can start a game, wait for something you like, hit one button, and get the whole BGM. Everything else I've seen requires you to log precisely, or hex edit the ROM.
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
byuu

Post by byuu »

I still don't know what you're talking about.
Then you aren't reading my posts. Indicate a yes/no after each statement if you understand. I will attempt to describe in more detail each no response.

1) DSPRAM = 256 bytes in your format.

2) Even though there is no DSPRAM, you can log all 128 registers in 128 bytes. This is half the size of the SPC file format's alloted space.

3) EXTRAM (the last 64 bytes of SPCRAM) is stored in DSPRAM[192] - DSPRAM[255]. This is sloppy, and leaves DSPRAM[128] - DSPRAM[191] as empty space.

4) IPLROM is stored at SPCRAM[0xffc0] - SPCRAM[0xffff]. This should not be stored here. Instead, EXTRAM should be placed here instead, and the extra 128 bytes of DSPRAM should be removed.
You're supposed to dump the SPC prior to a new BGM being loaded. ZSNES searches for the next one, and gets you the whole thing. It just means though you need proper human timing to get the audio.
Oh, neat. I wonder how it does that for all eight channels that can be playing BRR samples without hanging up frequently. That would explain why everything sounds good with no DSP/timer state data.
It seems to play everything but streaming audio. And AFAIK, it's the only format that you can start a game, wait for something you like, hit one button, and get the whole BGM.
Yes, it's a very neat format that takes advantage of the "black box" approach of the SPC700 and its DSP very well. And the best part is, there's no need to redump the files when SNES sound emulators get more accurate.
Nach
ZSNES Developer
ZSNES Developer
Posts: 3904
Joined: Tue Jul 27, 2004 10:54 pm
Location: Solar powered park bench
Contact:

Post by Nach »

byuu wrote: 1) DSPRAM = 256 bytes in your format.
The field with that name is 256 bytes.
byuu wrote: 2) Even though there is no DSPRAM, you can log all 128 registers in 128 bytes. This is half the size of the SPC file format's alloted space.
Um, it's 1/258 of the space in the file.
byuu wrote: 3) EXTRAM (the last 64 bytes of SPCRAM) is stored in DSPRAM[192] - DSPRAM[255]. This is sloppy, and leaves DSPRAM[128] - DSPRAM[191] as empty space.
Yes, and does it matter if it's sloppy?
byuu wrote: 4) IPLROM is stored at SPCRAM[0xffc0] - SPCRAM[0xffff]. This should not be stored here. Instead, EXTRAM should be placed here instead, and the extra 128 bytes of DSPRAM should be removed.
Okay.
So how is this relavent? If it stores what it needs to store, I don't see what the problem is. While I'd love to save space, it's bearable as is.
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
byuu

Post by byuu »

Alright then, 'good enough' mentality I suppose. Forget this perfectionist said anything.
creaothceann
Seen it all
Posts: 2302
Joined: Mon Jan 03, 2005 5:04 pm
Location: Germany
Contact:

Post by creaothceann »

byuu wrote:Speaking of which, are we ever going to fix the problems with the spec?
You'd probably be off better with a new file format. Preferably chunk-based. :wink: Fixing SPC would break too many programs.

The new format would also need a good player, eg. a Winamp plugin. :)
vSNES | Delphi 10 BPLs
bsnes launcher with recent files list
zones
New Member
Posts: 5
Joined: Sat Feb 11, 2006 3:36 am
Location: Japan

Post by zones »

FYI:
0) SPC format has a minimum of APU/DSP's usable information to play BGM 'good enough' and some unusable/unused parts.
1) SPC format assumes all the $f0-$ff values are stored in SPCRAM.
2) So sometimes you should modify $f1 after you load the SPC file.
3) It doesn't store any APU timers.
4) Far from perfect emulation.
5) For example Snes9x watches the key-on event and then writes the SPC file. It's 'good enough' for most BGMs.
6) Anyway some games, for example Furai no Shiren, need CPU emulation to play its BGM, in this case SPC format is helpless.
Nach
ZSNES Developer
ZSNES Developer
Posts: 3904
Joined: Tue Jul 27, 2004 10:54 pm
Location: Solar powered park bench
Contact:

Post by Nach »

Furai no Shiren streams the audio?
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
BRPXQZME
Hazed
Posts: 54
Joined: Tue May 30, 2006 3:47 am
Location: Centreville, VA
Contact:

Post by BRPXQZME »

According to SNESMusic.org, that's why they can't dump it.
Nach
ZSNES Developer
ZSNES Developer
Posts: 3904
Joined: Tue Jul 27, 2004 10:54 pm
Location: Solar powered park bench
Contact:

Post by Nach »

BRPXQZME wrote:According to SNESMusic.org, that's why they can't dump it.
Well then, for streamed audio, wave dumping is what is needed.

Strange, I don't see ToP's intro on that list.
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
BRPXQZME
Hazed
Posts: 54
Joined: Tue May 30, 2006 3:47 am
Location: Centreville, VA
Contact:

Post by BRPXQZME »

It isn't, but I don't know all the issues behind that one anyhoo.
zones
New Member
Posts: 5
Joined: Sat Feb 11, 2006 3:36 am
Location: Japan

Post by zones »

IIRC in Furai no Shiren CPU constantly watches a certain value from APU. I've forgotten the details.
FitzRoy
Veteran
Posts: 861
Joined: Wed Aug 04, 2004 5:43 pm
Location: Sloop

Post by FitzRoy »

Lord of the Rings does something strange as well.

I don't know the consequences of fixing the format, so I can't have an opinion on this. Obviously I want it done right, but the format is already so established.
www.zapatabase.com
Nach
ZSNES Developer
ZSNES Developer
Posts: 3904
Joined: Tue Jul 27, 2004 10:54 pm
Location: Solar powered park bench
Contact:

Post by Nach »

Well, if there was something that could be done, we could always bump up to 0.4.0, not that big of a deal (except all tools will have to update).

However I don't see how we're going to record streaming audio. The data simply isn't there yet.
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
byuu

Post by byuu »

Maybe a new format altogether would be a good idea for streaming audio. What about an "event log" that records DSP actions, rather than an SPC700 savestate?

I obviously haven't put too much thought into the specifics... but if we buffer all the BRR samples into a table, and then index the actions taken by the DSP each sample, we could then record theoretically anything. But the downside is you capture sound effects now, too. So you'd need special overrides to block certain channels (possibly even during certain times and such).

The good news is the format would be easier to support for playback... bad news is it'd be more work for emu authors to dump it.
Nach
ZSNES Developer
ZSNES Developer
Posts: 3904
Joined: Tue Jul 27, 2004 10:54 pm
Location: Solar powered park bench
Contact:

Post by Nach »

byuu wrote:Maybe a new format altogether would be a good idea for streaming audio.
It's called wave. Popular methods for compressing wave (and sometimes lossy) are ADPCM, MP3, MP4, OGG, FLAC...

I don't see what there is to gain by making something SNES specific for streaming.
May 9 2007 - NSRT 3.4, now with lots of hashing and even more accurate information! Go download it.
_____________
Insane Coding
byuu

Post by byuu »

For one, it's easier to manipulate. You can control channel key on/off masks, override pitch ranges, etc. Another is you don't have to redump the WAV when say a GAIN bug is fixed in the emulator that dumped it to get more accurate sound. Another is that this format would probably be smaller than a WAV, in theory at least. Which is the whole reason we use SPC instead of, as you put it, what's called wave.
Post Reply