Filling out the fields in the SPC file format

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Filling out the fields in the SPC file format
by on (#137784)
I'm working on a ca65 project template for SPCs assembled directly from source code. An early version is included with my LoROM project template. For example, a homebrew game developer could use this to offer a clean SPC rip of the game's soundtrack. But I don't know how to set up some of the fields listed in SPC and RSN File Format.

$24: "Version Minor (i.e. 30)"
This is decimal, correct?

$27: "A"
Is there a way to specify that all SPCs in a set are identical except for one register value without paying for WinRAR and making an RSN with multiple copies of the SPC that differ only by $27 (A) to select a song? It might be possible by including a Python script that duplicates the ROM, but the vast majority who uses Microsoft Windows as a primary operating system do not have a copy of Python installed. Should a set include a PowerShell script for Windows users and a Python script for everyone else?

$2E: "Song Title"
Are text fields like this space-padded or NUL-padded?

$6E: "Name of Dumper"
What goes here if the SPC was created by the artist?

$7E: "Comments"
What goes here?

$9E (binary format): "Date SPC was Dumped (YYYYMMDD)"
How are the 4 bytes allocated? Is it BCD or something else? Or is the "text format" more compatible?

$A9 (text format): "Number of Seconds to Play Song before Fading Out"
Is this zero-padded on the left, space-padded on the left, space-padded on the right, or NUL-padded on the right? Also, nobody needs more than 16 minutes and 39 seconds in the same way that nobody needs more than 64K.

$A9 (binary format): "Number of Seconds to Play Song before Fading Out"
I'm assuming little endian. Am I right?

$D2 (text format), $D1 (binary format): "Emulator used to dump SPC (0 = Unknown, 1 = ZSNES, 2 = Snes9x)"
Should SPCs assembled from source just use 0?

$101C0: "Extra RAM (Memory Region used when the IPL ROM region is set to read-only)"
What is this? Is this supposed to be a copy of the IPL ROM, or the memory "behind" the IPL ROM? Should the IPL ROM be stored at $100C0 in the file ($FFC0 within the RAM segment)? For songs that don't themselves call the IPL ROM other than to "quit", how critical is it that the data stored here match the actual IPL ROM?

Why are the metadata fields called ID666 anyway? I understand ID<number> because of ID3, a metadata extension to MP3 audio files. But why the 666?
Re: Filling out the fields in the SPC file format
by on (#137788)
For the text files I'd recomend to leave all them to 0x00, this is valid, as ID66 is not mandaotry in the SPC standard.

Quote:
or the memory "behind" the IPL ROM?

My understanding is that if the IPL ROM is enabled at the time of the dump, it is present at 0x100c0 and the memory "behind" it at 0x101c0. Buf it IPL ROM is disabled at the time of the dump, the memory "behind" it is naturally present at 0x100c0. This feature is absolutely ridiculous and useless, as storing the IPL ROM in SPC files makes absolutely no sense whatsoever. I don't even know how many SPC players supports this distinction, but I wouldn't be surprised if each one behaves in a completely different way.
Re: Filling out the fields in the SPC file format
by on (#137932)
The point of storing the IPL rom was in case anything referenced it accidentally or from cleverness. I can't be 100% sure because I've never done audio programming, but it might be necessary because of the (poorly named) concept of SPC Rape, sometimes called Square Rape. Executing data as code, or code as sound data...

For example, from what I can remember the wind noise is done this way. Sounded absolutely ridiculous until the audio module was almost perfectly emulated.


Tepples: maybe try asking kode54 of foobar2000 about these nuiances? He's definitely still around.
Re: Filling out the fields in the SPC file format
by on (#137936)
whicker wrote:
Executing data as code, or code as sound data...

For example, from what I can remember the wind noise is done this way. Sounded absolutely ridiculous until the audio module was almost perfectly emulated.

No. The FF6's and Chrono Triggers' wind noise who-was-sounding-ridiculous-in-old-emulators-and-spc-players is done with a pseudo-white noise sample, which is made by decoding a loud sine-like wave and abusing the BRR decoding hardware's behaviour on overflow into an unstable chaotic number sequence generator. This has the enormous advantage of storing a long pseudo-random sequence using only a very short amount of memory.

1) It has nothing to do with executing data as code or code as data
2) It has nothing to do with IPL ROM
3) Not only Square, but also Capcom and other companies used this technique
4) Whoever came with the "rape" name is retarded, it's the first time I hear about this
Re: Filling out the fields in the SPC file format
by on (#137960)
Alright,

But we're back to: Is it theoretically possible to write a sound program that, in order to function correctly, requires the IPL ROM data to be bit perfect and immune to writes?
Re: Filling out the fields in the SPC file format
by on (#137962)
Yes ?

But that doesn't mean the IPL ROM has to be stored in the .spc file, it should be stored in the replayer itself.
Re: Filling out the fields in the SPC file format
by on (#138251)
Quote:
$24: "Version Minor (i.e. 30)"
This is decimal, correct?

I write decimal 30 when I create SPC files.

Quote:
$2E: "Song Title"
Are text fields like this space-padded or NUL-padded?

I NUL-pad.

Quote:
$6E: "Name of Dumper"
What goes here if the SPC was created by the artist?

The name of the artist?

Quote:
$7E: "Comments"
What goes here?

Anything you like. I suppose you could fill it with NUL-bytes if you want to.

Quote:
$9E (binary format): "Date SPC was Dumped (YYYYMMDD)"
How are the 4 bytes allocated? Is it BCD or something else? Or is the "text format" more compatible?

SNESAmp does the following for binary ID666 tags:
Code:
y = *(u16*)(&spc.date[2]);
m = *(u8*)(&spc.date[1]);
d = *(u8*)(&spc.date[0]);

Where spc.date contains the actual 4 bytes from the tag.

Quote:
$A9 (text format): "Number of Seconds to Play Song before Fading Out"
Is this zero-padded on the left, space-padded on the left, space-padded on the right, or NUL-padded on the right? Also, nobody needs more than 16 minutes and 39 seconds in the same way that nobody needs more than 64K.

SPCAmp calls atoi() on the string, so I assume NUL-padded on the right.

Quote:
$A9 (binary format): "Number of Seconds to Play Song before Fading Out"
I'm assuming little endian. Am I right?

This is what SPCAmp does:
Code:
i = *(u16*)(songStr);
if (i > 959) i = 959;

Where songStr contains the 3 bytes from the tag.

Quote:
$D2 (text format), $D1 (binary format): "Emulator used to dump SPC (0 = Unknown, 1 = ZSNES, 2 = Snes9x)"
Should SPCs assembled from source just use 0?

That's what I do. But the addendum for v0.31 of the SPC format spec says that "The current Win32 version of ZSNES saves binary SPC files; SNES9x saves in text format". So you might want to keep that in mind to make it easier for players to detect the ID666 format you're using.

Quote:
$101C0: "Extra RAM (Memory Region used when the IPL ROM region is set to read-only)"
What is this? Is this supposed to be a copy of the IPL ROM, or the memory "behind" the IPL ROM? Should the IPL ROM be stored at $100C0 in the file ($FFC0 within the RAM segment)? For songs that don't themselves call the IPL ROM other than to "quit", how critical is it that the data stored here match the actual IPL ROM?

I just fill this area with zero-bytes.