MSU1 Media Enhancement
The Abridged Specs


Essentially SNES-CD in the form of an emulator expansion chip. Also sometimes known as a "fancy ROM". Yet another project in a long line of Near's (Byuu's) work. It's supported in Snes9x (SNES only), higan (also with SGB), bsnes (also with SGB), and FX Pak (SD2SNES and also with SGB). Supports both audio streaming (through MSU1-formatted .pcm files) and general data streaming (including FMV, through an .msu data file).

The datafile must be present to enable MSU1. If a datafile isn't needed, then it can simply be left empty. Two known versions exist - version 1 is the initial specifications from 2012. Version 2, first supported in higan v0.96, added the "resume" bit in the track control register.




The MSU1 registers uses CPU addresses $2000 to $2007. A breakdown of its functions for R/W is as follows.
Address Read Write
$2000 MSU1 status Data seek
$2001 Data read
$2002 Identification
$2004 Track number
$2006 Track volume
$2007 Track control

$2000 (R) - Status

This register contains current information about the MSU1's state. The following bits map to these MSU1 states.
7 6 5 4 3 2 1 0
Data busy Audio busy Audio loop Audio playing Track missing Version

Bits 0-2 indicate the current version of the MSU1 present. It can be used to check for a specific feature, such as track resume.

Bit 3 is set when the MSU1 cannot find some audio track to be played. This allows fallback to SPC700 music for select tracks.

Bits 4-5 can be read to determine if an audio track is playing or is a looping track.

Bit 6 is set when the MSU1 is currently reading an audio track. This effect is more obvious under slow hard drives or through the FX Pak, which includes the MSU1. You may check for this bit by using these instructions:

	bit $2000
	bvs audio_busy	; branch if audio is busy.

Bit 7 is set when the MSU1 is currently reading from the data file. You may check for this bit by using these instructions:

	bit $2000
	bmi data_busy	; branch if data is busy.

$2000 - $2003 (W) - Seeking

These registers denote a 32-bit address in little-endian ($2000 is the Least Significant Byte). For example, a seek to address $524C would mean a write to $2000 in the form of: 4C 52 00 00. The last write to $2003 triggers the seek, and will set the "Data busy" bit on $2000 until done.

$2001 (R) - Data read

If a read is done on this port, then it will return the data from the current position in the data file, followed by the MSU1 incrementing the seek address on the file. Any read from this register requires the "Data busy" bit on $2000 be cleared. Reading from the data file won't work otherwise.

$2002 - $2007 (R) - Identification

When read from these addresses, it returns the expansion chip's identification string / "magic number". It should be a 6-byte string spelling "S-MSU1" in ASCII, in order (big-endian). This may be checked so that the game may still provide SPC700 music if the chip is not present.

$2004 - $2005 (W) - Set track number

This is a 16-bit number in little endian ($2004 is the Least Significant Byte), therefore a maximum of 65536 audio tracks can be supported. As with the seek register, the write to the last byte ($2005) triggers the audio load, and as such will set the "Audio busy" bit until the track finishes loading.

$2006 (W) - Set track volume

This number scales linearly, from $00 = 0%, $80 = 50%, and $FF = 100%.

$2007 (W) - Track control

This register controls MSU1 audio playback. The following bits map to these conditions.
Revision 7 6 5 4 3 2 1 0
1 (reserved) Looping Play
2 (reserved) Resume Looping Pause/Play

After setting the track number, the audio can then be set to be played by writing to this register, primarily by using bits 0-1, where bit 0 is set so that it may be played, and bit 1 is set if the audio is desired to be looped.

Resetting bit 0 will stop the track. However, version 2 adds the ability to resume the audio track by setting bit 2. It might be possible to load and play another audio track, then return to the previous track by loading it again and immediately setting bit 2 to resume it.

Keep in mind that any write to this register will require the "Audio busy" bit on $2000 be cleared.

Data Files

[ROM name].msu (bsnes) - msu1/data.rom (higan)

Only one of these is required, and it must match the .sfc ROM name, only changing the .sfc to .msu. It stores additional data that should be loaded / streamed directly into SNES memory such as additional level data or FMV.

If the MSU1 is needed for audio streaming only, this file should still be present but left blank, through e.g. touch [ROM name].msu, or by making a new text file and renaming it to [ROM name].msu.

[ROM name]-[number].pcm (bsnes) - msu1/track-[number].pcm (higan)

These are audio files to be streamed by the chip, where [ROM name] matches the .sfc ROM name, and [number] is the MSU1 track index in decimal, without leading zeroes. For example, if $0010 is written (as little-endian) to the track number register, then the file [ROM name]-16.pcm will be loaded for streaming. The maximum file size allowed is 16 GB, or about 27 hours of audio.

These are 16-bit, stereo (left first), little-endian PCM files at 44100 Hz with a simple 8-byte header, resulting in the following format:
Position Data Comment Size
0 4D 53 55 31 "MSU1" in ASCII 4
4 xx xx xx xx Loop point (in samples) as a 32-bit unsigned number in little-endian. If loop is undesirable, it should be set to all zeroes. 4
8 xx xx yy yy, xx xx yy yy, ... Stereo samples, each 16-bit signed little endian. Left sample, right sample, left of next sample, right of next sample, and so on. (variable)

This means that they are effectively .WAV files. You can make one in Audacity by loading any audio file, saving it as a "RAW (header-less)" file (under Export -> format dropdown -> "Other uncompressed files") with the "Signed 16-bit PCM" encoding. Then, load the exported file in a hex editor and prepend the 8-byte header before the data.

To make this process easier, use a tool such as msupcm++, which takes in a JSON file and outputs a bunch of .pcm files from any audio format (flac / wav)

These PCM files can be played back in ffplay (without looping): ffplay -ar 44100 -ac 2 -f s16le something.pcm or in foobar2000 using foo_input_msu.


Sample code