Category Archives: Uncategorized

Blargg snes_spc SPC Export


This blog reveals exporting an SPC from Blargg’s snes_spc 0.9.0, my custom blend of snes_spc 0.9.0 and gme, and its stock limitations.

and now some random but maybe useful info

struct track_info_t
	long track_count;
	/* times in milliseconds; -1 if unknown */
	long length;
	long intro_length;
	long loop_length;
	/* empty string if not available */
	char system    [256];
	char game      [256];
	char song      [256];
	char author    [256];
	char copyright [256];
	char comment   [256];
	char dumper    [256];
enum { gme_max_field = 255 };

SPC Export

Write Header

Basically a home-shopped routine to write the header info will be required. Some combination of the Spc_Emu::header_t will make it happen..


// SPC file header
enum { header_size = 0x100 };
struct header_t
  char tag [35];
  byte format;
  byte version;
  byte pc [2];
  byte a, x, y, psw, sp;
  byte unused [2];
  char song [32];
  char game [32];
  char dumper [16];
  char comment [32];
  byte date [11];
  byte len_secs [3];
  byte fade_msec [4];
  char author [32]; // sometimes first char should be skipped (see official SPC spec)
  byte mute_mask;
  byte emulator;
  byte unused2 [46];
// Header for currently loaded file
header_t const& header() const { return *(header_t const*) file_data; }

The SPC Export routine can use the header() when exporting an SPC that already has a header, but here’s how the GUI should do things:

There will be a File -> Export -> SPC button in the Menu_Bar class. For this, another feature to Expanding_List must be added.. allowing a menu_item to trigger the presentation of another array of menu_items to the right of it. And event processing thereof.

But anyways, when the export SPC button is pressed, a new window must display that allows the user to customize the SPC header entries. Any other customizations that would be necessary?

Writing the Rest of the SPC is easy

Today I discovered how to do this to the best of the emu’s abilities (snes_spc 0.9.0) — I’ll keep saying there is potentially a new version of snes_spc/gme at SNES_GSS google code but I don’t bother to look at it. Here’s what I discovered.

The best it can currently do is export an SPC after having already loaded one, and it exports with a blank header. So some ID666 routines will need to be invented to write a proper header, and inspiration will surely come from this website.

Here is how to do the magic…

void make_save_state( const char* path )
	/* Load SPC */
	long spc_size;
	void* spc = load_file( path, &spc_size );
	error( spc_load_spc( snes_spc, spc, spc_size ) );
	free( spc );
	spc_clear_echo( snes_spc );
	/* Skip several seconds */
	error( spc_skip( snes_spc, 60 * spc_sample_rate * 2) );
	/* Save state to file */
		static unsigned char state [spc_file_size]; /* buffer large enough for data */
		unsigned char* out = state;
// then write header here
		spc_save_spc( snes_spc, out );
		write_file( "state.spc", state, spc_file_size );
	record_wav( "first.wav", 5 );

The problem is that spc_init_header() also writes that the ID666 is not present [lie], so that will have to be set to present.. the value to say ID666 is 27 or 0x1a and that DOES get written. Then, the spc_file_t entry importance is text[212], which includes the first two bytes of which are unused. so text[2] begins the song_title etc.. and is where the… no wait, FYI spc_file_t and header_t point to the same memory structure 🙂


struct spc_file_t
char    signature [signature_size];
uint8_t has_id666;
uint8_t version;
uint8_t pcl, pch;
uint8_t a;
uint8_t x;
uint8_t y;
uint8_t psw;
uint8_t sp;
char    text [212];
uint8_t ram [0x10000];
uint8_t dsp [128];
uint8_t unused [0x40];
uint8_t ipl_rom [0x40];

Gain,Volume Zipper Pop Suppression by Steady Zero Crossing Technique

This post is accompanied by a video hosted at

This PDF says it all: zipper_gain_clicks

Baring in the mind that I have not yet controlled a strict frame rate in my program, my code looks something like this:

double Audio::calculate_linear_gain_from_db(double gain_db, double min_gain/*=-96.0*/)
  if (gain_db <= min_gain) return 0.0;  // -INF dB
  else return pow ( 10.0, (0.05 * gain_db) );

void Music_Player::apply_gain(sample_t* out, int count )
  double gain; 
  double direction;

  gain = Audio::calculate_linear_gain_from_db(gain_db, min_gain_db);
  for (int i=0; i < count; i += 1)
    double newsamp = out[i];
    if (gain_has_changed)
      direction = ((new_gain_db - gain_db > 0) ? +0.02 : -0.02);

      if ((newsamp <= 0.0 && out[i+1] > 0) || (newsamp >= 0.0 && out[i+1] < 0))
        gain_db += direction;
        if ((direction > 0 && gain_db >= new_gain_db) || (direction < 0 && gain_db <= new_gain_db))
          gain_db = new_gain_db;
        gain = Audio::calculate_linear_gain_from_db(gain_db, min_gain_db);
    //DEBUGLOG("gain = %f\n", gain);
    newsamp *= gain;
    int io = round(newsamp);
    /*if (d > 32767)
      d = 32767;
    else if (d < -32768)
      d = -32768;
    if ( (int16_t) io != io )
    /*fprintf(stderr,"\t%d : ", io);*/
      io = (io >> 31) ^ 0x7FFF;
    /*fprintf(stderr,"\t%d\n", io);*/
    out[i] = (sample_t)io;

Support for RSN

RSN is a popular method for packaging together a bunch of SPCs (ie. anything on I want to be able to work with these in STD. Don’t tell me why people decided to use RAR for a standard SPC compressed format. It’s proprietary :[
Fortunately, the usage rights of Unrar seem pretty liberal.

I’m considering compiling externally the unrar application, and including as part of the SNES Tracker package. SNES Tracker / STD will call it upon it from source manually — but can that be done in a portable manner?? This is the golden question… Alternatively, would it be easier to learn the source level of the unrar application and incorporate it directly into the SNES Tracker application? Are there still portability issues with this??

I feel that I can probably keep the application external, and probably have some simple preprocessor logic to do the right thing based on *nix / Windows based system..

I don’t know the traditional approach, so I’m thinking of the following approach..
Use SDL_GetPrefPath to get a portable base path, then create a tmp folder inside it.
Extract a rsn into that tmp folder and proceed to open all files inside it…
Remove the contents of the tmp directory at program cleanup/exit.

I just read this on a forum: “Prefer ‘/’ over ‘\\’. ‘/’ works on Windows and pretty much everything else. ‘\\’ works only on Windows and on nothing else. Also ‘/’ tends to be less error prone because \ is the escape character.” — How true is this??? Or rather, how old a version of Windows does apply?? Seems safe, I’ll rely on this.

Play SPC Intrument

// backup_pc()
uint16_t *pc_ptr = (uint16_t*)&IAPURAM[report::last_pc];
uint16_t pc_backup = *pc_ptr;

// write with never-ending loop
#define ENDLESS_LOOP_OPCODE 0xfe2f
// overwrite_pc_with_endless_loop()


// restore_pc()
uint16_t *pc_ptr = (uint16_t*)&IAPURAM[report::last_pc];
*pc_ptr = pc_backup;

Ripping Continued

NOTE: this post is just “thought jots” and the official formats are going to be different 😛 You’ve been warned

There will be 2 new file formats.. which are being developed.. this isn’t final.
BRR is the plain ol’ sample
BRR-Plus (BRR+) (.brrp) contains a 2byte loop offset directly after the BRR sample
BRR-instrument (.brri) / SNES-instrument / SPC-instrument will contain:

Loop offset (2 bytes)
ADSR1,2 (2 bytes)
GAIN (1 byte)

As far as ripping the samples go. I am in the notion that you’re watching the STD memory debugger, and see samples being played.. You right-click a sample region and get a box

Download BRR
Download BRR-Plus
Download Instrument
Play Instrument

But I want to focus today on Download Sample and how to calculate the correct portion. There is a possibility for slight error but mostly working copy: All BRR-END locations are already known. DIR has the start-locations and loop point information. Program must do the following:

in report namespace, append BRR_End[100]
As BRR end headers are found, check the array if they already exist or add them otherwise.. Be sure to add 9 to the brr header block address. i dunno how the performance will be. We'll get there.
When the user right-clicks on the memory region (SDL Event), find the closest entry in array that is above the user's clicked address..
get the DSP DIR * 0x100
Inspect the IAPURAM DIRECTORY for the address that is closest to user clicked address and is < userclicked address. then we have start_addr and end_addr

Organize the package for downloading:
design struct

Ripping BRR Samples

I can see that BRR samples are being played.. How can my app be smart
enough to identify this, when the user clicks/right-clicks to RIP Sample?
First we need to decide to enable the “RIP Sample” button.. What decides that?
If the user clicks on a portion of memory that contains a BRR Sample..
This means he may have clicked anywhere in the midst of the 9-byte Blocks

There can be an (dynamic) array of BRR-END block locations, which for now will just be static [100]..
this array must be accessible by the Spc_Dsp class as well (report.h/cpp is the current best place
for this). When the DSP encounters a BRR End block, it will add it to the array.. the array is
delimited by a zero-entry.

The app thinks, “If I see an area of memory being accessed continuously that includes a BRR END block,
I can go back until either the lowest accessed memory of the same amount of accesses,
or I can go back until the END block before it and add 9.”

But what would be coolest is a “Sample Ripper.”
“I Found 9 Samples”
with a menu to listen to each of them with the ability to play them at different pitches on your keyboard just like the tracker.. In fact, this will probably derive from the same “Sample Editor” interface or share a common component or 2 at the least.

Creating good Samples in SNES Conditions

here is a log from #BoTB that has some highlights regarding Gym’s Advice on SPC Sample modeling. Full post thrown at the end of this page…

17:37 bazz: gyms: I read a post of yours about SubHarmonics / getting the most out of your samples on the SPC.. Good read, but was the fancy terminology just eluding towards layering a +-1 octave with lower volume?? What about when the +1 octave becomes shorter wavelength. Are you forced to trim your whole sample?
17:37 gyms: bazz, yea basically. with layering the same sample, it's probably best to use an algo that pitches stuff around without stretching it. but you could also layer w/e you want i suppose, doesn't have to be the same sample...however i thought layering the same sample would be a good idea if all you wanted to do was add a bit of brightness without changing the original sound too drastically.
17:39 bazz: gyms: you mentioned using audacity.. I use that too. does that tool have an algo as such?
17:39 gyms: i don't think it does :x
17:45 gyms: bazz actually it seems the Change Pitch effect in audacity is changing the pitch without affecting the length (?)

17:46 Joltik: Change speed ajusts length and pitch
17:46 Joltik: Change pitch introduces tons of grain though
17:46 Joltik: The solution I usually go for is sliding time scale/pitch shift
17:47 Joltik: You just set it to start and end at the same pitch
17:47 Joltik: a lot less grainy than just pitching it up
17:47 gyms: if you were gonna do a subharmonic, i’d just layer in a sine wave
17:48 gyms: there was another way to use harmonics as an arrangement trick
17:49 gyms: which is hard to explain
17:49 gyms: i think i tried to explain it briefly on my thingy
17:49 bazz: when you say sub-harmonic, is that equivalent saying “lower octave” ?
17:49 gyms: yeah
17:50 gyms: it comes down to playing around until you find something that fits the best


23:00 Joltik: Resample things without adjusting speed?
23:01 gyms: but yeh, i suppose in general you gotta pay yer dues in some circle of employment for a while
23:01 Joltik: adjust pitch without speed yes?
23:01 bazz: yes.. but i was interested in that complex answer u had, not just “use the adjust pitch effect” like gyms recommended
23:01 vita3 has joined (
23:02 Joltik: There should be a “Sliding Time Scale/Pitch Shift” effect
23:02 Savestate has left IRC (Ping timeout: 198 seconds)
23:02 Flaminglog_: that’s a really fun effect
23:02 Daverd: bazz i think it involves FFTs
23:02 Joltik: Just set the start pitch and the end pitch to the same pitch
23:02 Flaminglog_: and gyms yeah, i just wish i hadn’t wasted three years working at a grocery store lmao
23:02 Joltik: Gives a much smoother result than the Change Pitch effect
23:03 bazz: that’s the ticket! I knew I was interested for a good reason.. But, and do please try to keep it simple, why is that smoother than the “Change Pitch” effect?
23:08 Daverd: wow this actually does sound pretty good
23:10 Daverd: yeah, why is that??
23:11 Daverd: wtf audacity, why not use that for the adjust pitch effect

full post:
“hey i wanted to share a little technical something i stumbled onto lately with snes sound design.

i often run into problems using the more ‘sophisticated’ samples, aka more complex waveforms like flutes, strings, etc(stuff that’s not simple chippy waveforms) in that they usually either sound too muddy or too thin for how i end up using them in my cramped 8 channel arrangement.

the problem is of course working with these lower sample rates. there’s just not much harmonic content, so you have to really stick close to the notes where they were orginally sampled…but even then things can get muddy or thin.

i’ve read interviews, some of the old snes composers lamented over how difficult it was to get a set of samples that sounded good together. “once you finally found some that worked well together, of course you’d keep using them over and over in other games…”

anyway, i was doing a midi transcription of the snes rainbow road yesterday and discovered something really neat that happens soon after the intro:

when the xylo-sound first comes in, the melody D-E-F-G-D etc, it’s set in the fifth octave. arrangement wise it belongs up there because all the brass stuff is happening an octave below, however i noticed my midi arrangment sounded quite thin and weak with it up there in the fifth octave.

there was something unique going on within the mariokart xylo sample itself, so i decided to take a closer look:

there’s a subharmonic in there! when i applied the subharmonic with a similar ratio to my midi transcription, it sounded just right. there are also a lot of other very clever things they did with their samples, but i’ll save that for another time.

so what does this mean?

it means that you can use acoustics to your advantage to further overcome the challenges of low fidelity and limited channels. there are samples that have a similar 3:1 or 5:1 ratio applied to the first octave above the fundamental to give it a bit more presence.

also it’s good to keep in mind is that that overtones contain harmony within them! snes mariokart used this to their advantage as well, they did a lot of really clever things. when considering an arrangement and how to make it sound deep and full with samplerate-dictatedly dull samples and limited channels, you can use harmonics as a way to simultaneously augment your arrangement while adding harmonic excitement.

PRACTICAL BOTTOM LINE: if your sample is feeling a bit too thin, add a subharmonic an octave below. if it’s too muddy, try layering a pitched up copy of itself an octave above. make sure to lower the volume of your added harmonic, a 3:1 fundamental to harmonic ratio is a good starting place.

you can do this with audacity: just layer two instances of a sample over one another, pitch one up/down an octave and then lower its volume. keep playing with the ratio and check how it sounds in your song until it sounds the way you want.

there’s also ways you can muck with harmonics via loop points, but i prefer to just edit and resample. audacity does the trick. and of course the snes delay brings life to things as well…”– Gyms