Nintendo MP3 Player Technical Documentation 0.1
October 30, 2023
Shonumi aka D.S. Baxter


***************************************************
1. Introduction
*************************************************** 

Following in the footsteps of the original Play-Yan and Play-Yan Micro, the Nintendo MP3 Player was launched in Europe on December 8, 2006. This unique cartridge was very similar to other products in the AGS-006 lineup. Now, however, the device played MP3 music files exclusively, getting rid of any video playback components. Due to this change, the underlying hardware and software had significant differences from the earlier Play-Yans.


***************************************************
2. General Hardware Information
***************************************************

- Features a normal-sized SD card reader.
- Can handle card capacities up to 2GB, depending on the manufacturer.
- Not compatible with SDHC, SDXC, or SDUC cards.
- Uses hardware decoding. Not an Alpha Mosaic VC01 like previous Play-Yan models.
- Uploads firmware on boot, and can optionally update with the correct files on an SD card.
- Features a slightly larger than normal cartridge shell.
- Has a 3.5mm audio jack to output sound and bypass the GBA's speakers.
- Can parse some ID3 tags (ID3v1, ID3v1.1, ID3v2, and mixed ID3v1/ID3v2 tags).
- Supports MP3 bits rates of 32k to 320k bps, CBR, VBR, and ABR.
- Supports sampling frequencies of 8KHz to 48KHz.


***************************************************
3. Hardware Registers
***************************************************

The Nintendo MP3 Player uses a very small selection of registers in the 0xE000000 memory region, relying on serial reads and writes to access firmware, send commands, and handle audio playback.

----------------------------------------------------------------------------------------------------------------------
Hardware Register	|  Address	| Description
----------------------------------------------------------------------------------------------------------------------
NMP_CONTROL		| 0xE000000	| Control register used to issue commands and send data to the cartridge.
NMP_DATA_IN		| 0xE004000 	| Input data for the cartridge.
NMP_DATA_OUT		| 0xE006000	| Output data from the cartridge.
NMP_PARAMETER		| 0xE008000	| Selects data indices and commands.
----------------------------------------------------------------------------------------------------------------------

All registers are 16-bit and MSB first. As such, care must be taken when reading/writing with hardware that is LSB-based (such as the GBA's ARM7 CPU). Additionally, due to the serial nature of the registers, the lower value must always be read/written first. The NMP's software, resorts to accessing these registers one byte at a time (e.g. 0xE000000 first, then 0xE000001) to resolve both issues.


***************************************************
4. Accessing Firmware
***************************************************

Like the original Play-Yan and Play-Yan Micro, the NMP loads default firmware from the cartridge's ROM onto special hardware inside the device. This ensures a baseline, working version of the firmware necessary to decode MP3s is always present, especially in case a firmware upgrade goes awry. To write firmware, the software first sets an index, presumably representing a location in internal memory where the firmware resides. Afterwards, it starts writing values. The index itself is expressed in terms of 16-bit units, so the absolute memory location is twice the value of the index.

The following process is used to access firmware:

------------------------------------------------------------------------
NMP_CONTROL_LO = 0x10
NMP_CONTROL_HI = 0x10

NMP_PARAMATER_LO = INPUT_PARAMETER_HI
NMP_PARAMETER_HI = INPUT_PARAMETER_LO

NMP_CONTROL_LO = 0x00
NMP_CONTROL_HI = 0x00

NMP_PARAMATER_LO = INDEX_HI
NMP_PARAMETER_HI = INDEX_LO
------------------------------------------------------------------------

From there, data can be read or written by from either NMP_DATA_IN or NMP_DATA_OUT as 16-bit values. It is currently unknown what purpose the different values of INPUT_PARAMETER serves. Common values appear to be 0x0000 through 0x0003.

Although the Nintendo MP3 Player has the ability to update its firmware just like its Play-Yan predecessors, it's unclear if this was actually ever done for this version. The cartridge specifically looks for a file named "meteor.fup", but it does not appear any such file was ever offered to users by Nintendo.

After the firmware is completely loaded from the NMP's ROM, a single Game Pak IRQ is automatically generated, which begins the boot process, very similar to how the Play-Yan models operate.


***************************************************
5. Index Overview
***************************************************

While most indices appear to be used for accessing firmware, some have other purposes. These are accessed in a similar manner to firmware. Here, however, the value representing INPUT_PARAMATER is always 0x0000:

------------------------------------------------------------------------
NMP_CONTROL_LO = 0x10
NMP_CONTROL_HI = 0x10

NMP_PARAMATER_LO = 0x00
NMP_PARAMETER_HI = 0x00

NMP_CONTROL_LO = 0x00
NMP_CONTROL_HI = 0x00

NMP_PARAMATER_LO = ACCESS_INDEX_HI
NMP_PARAMETER_HI = ACCESS_INDEX_LO
------------------------------------------------------------------------

A list of known indices and their functions follows:

------------------------------------------------------------------------
Index	| Description
------------------------------------------------------------------------
0x0000	| Access SD Card Data
0x00FF	| Data Flush
0x0100	| Get Game Pak IRQ Status Data
0x0101	| Access ID3 Data
0x010F	| Send Command / Get Ticks
0x0110	| Check Cartridge I/O Busy Flag
0x----	| Left Audio Buffer
0x----	| Right Audio Buffer
------------------------------------------------------------------------

Index 0x0000 : Access SD Card Data
This index is accessed after issuing a command that expects to receive data from the SD card. That data is available at NMP_DATA_OUT.

Index 0x00FF : Data Flush
This index typically accessed after commands are issued. It seems like it's used to flush input data. After accessing this index, 16-bits are written to NMP_DATA_IN, with the value being 0x0000.

Index 0x0100 : Get Game Pak IRQ Status Data
This index is accessed immediately following a Game Pak IRQ. The NMP's software reads 16 bytes of status data from NMP_DATA_OUT related to the recent IRQ. This status data contains the Command ID associated with the IRQ as well as any additional parameters for the command. These parameters are used to update various things such as the music trackbar, music timestamp, fast forward/rewind, speed, volume, etc. Typically, the NMP's software will read the first 8 bytes of status data to determine if it's valid, then proceed to read the entire 16 bytes.

Index 0x0101 : Access ID3 Data
This index is access after issuing the 0x0040 command. Data for ID3 tags is available at NMP_DATA_OUT.

Index 0x010F : Send Command / Get Ticks
This index has two uses when writing to NMP_DATA_OUT and when reading from NMP_DATA_IN. When writing, it is used to send a command. A series of 16-bit values are then written to NMP_DATA_OUT. When reading, this access gets the current internal "ticks" from the NMP. A single 16-bit value is read from NMP_DATA_OUT, which is used as a measurement for time-keeping. For the most part, the NMP's software wants to ensure that the hardware is actually running, i.e. the 16-bit ticks values should increase periodically. The software reads it once per-frame and times out several actions if the ticks haven't advanced for a full second (i.e. during the initial boot phase, it will completely reset everything and try re-uploading firmware).

Index 0x0110 : Check Cartridge I/O Busy Flag
This index is accessed immediately following the last access to 0x0100. It's used to get the cartridge's I/O busy status. After accessing this index, a single 16-bit value from NMP_DATA_OUT is read. Any non-zero values indicate that the cartridge is still busy, presumbly with data from a previous Game Pak IRQ. This index can be accessed indefinitely until NMP_DATA_OUT returns zero, at which point additional commands can be issued.

Index 0x---- : Left Audio Buffer
This index is accessed after issuing the 0x0050 command and the NMP generates internal Game Pak IRQs with a Command ID that reads 0x8100. The status data for those internal IRQs will have 16-bit values that determine the exact index the NMP will assign for its audio buffers. This value appears arbitrary, so the index may not have a fixed position. The data is available at NMP_DATA_OUT and represents 8-bit samples compatible with the GBA's DMA sound channels. These samples, must be read in 16-bit units, however. When reading these samples with the GBA CPU, the MSB represents the first sample, while the LSB represents the second sample.

Index 0x---- : Right Audio Buffer
This index is much the same as the Left Audio Buffer. Accessing this will pull up the second portion of the overall audio buffer, which contains 8-bit samples packed in 16-bit units. The only thing different about this index is its location. See further notes below regarding how the exact index is calculated.


***************************************************
6. Reading SD Card Data
***************************************************

SD Card Data can be accessed after a Game Pak IRQ is raised in response to a command. Simply access the 0x0000 index and read data from NMP_DATA_OUT. The process is as follows:

------------------------------------------------------------------------
NMP_CONTROL_LO = 0x10
NMP_CONTROL_HI = 0x10

NMP_PARAMATER_LO = 0x00
NMP_PARAMETER_HI = 0x00

NMP_CONTROL_LO = 0x00
NMP_CONTROL_HI = 0x00

NMP_PARAMATER_LO = 0x00
NMP_PARAMETER_HI = 0x00


DATA_BYTE_HI = NMP_DATA_OUT_HI
DATA_BYTE_LO = NMP_DATA_OUT_HI
...
... REPEAT READS AS NECESSARY
...
------------------------------------------------------------------------

Commands expect different lengths of data from the SD Card, so there is no set general set limit. Bytes should be read according to the specific command and its context (e.g. an IRQ with a Command ID of 0x8100 may have variable lengths of bytes to read for the audio buffer).


***************************************************
7. Commands
***************************************************

Commands can be sent to the Nintendo MP3 Player after accessing the 0x010F index. Data consists of a stream of 16-bit words written to NMP_DATA_IN. These commands are responsible for operating nearly everything about the cartridge, from upgrading firmware, reading directory information from the SD card, and playing music. The process of sending a command is as follows:

------------------------------------------------------------------------
NMP_DATA_IN_LO = COMMAND_ID_HI
NMP_DATA_IN_HI = COMMAND_ID_LO

NMP_DATA_IN_LO = PARAMETER_VALUE_HI
NMP_DATA_IN_HI = PARAMETER_VALUE_LO

...

NMP_CONTROL_LO = 0x04
NMP_CONTROL_HI = 0x04
------------------------------------------------------------------------

At a minimum, a command must write its ID and an additional 16-bits of parameter data. Some commands, such as 0x10, use zeroes for their parameter data, and do not seem to require a flush via the 0xFF index. For commands that require more bytes for parameters, that data is simply written accordingly to NMP_DATA_IN. Writing 0x0404 to NMP_CONTROL appears to signal to the cartridge that command input is finished. A list of all known commands and details about them are listed below:

----------------------------------------------------------------------------------------------------------------------------------------------
Command	ID				| Parameters				| SD Card Data
----------------------------------------------------------------------------------------------------------------------------------------------
0x0010 - Begin File/Folder List		|					| 1 File/Folder Entry
0x0011 - Continue File/Folder List	|					| 1 File/Folder Entry
0x0020 - Change Directory		| Directory Name			|
0x0030 - Unknown Command		|					|
0x0040 - Grab ID3 Data			| Music Filename, Access Index		| ID3 Tags For Title and Artist
0x0050 - Play Music File		| Music Filename			|
0x0051 - Stop Music Playback		|					|
0x0052 - Pause Music Playback		|					|
0x0053 - Resume Music Playback		|					|
0x0060 - Seek Forwards/Backwards	| Stream Position, Seek Direction	|
0x0070 - Unknown Command		|					|
0x0080 - Adjust Volume			| New Volume				|
0x0200 - Play Sound Effect		|					|
0x0300 - Check For Firmware File	| Firmware Upgrade Filename		|
0x0301 - Read Firmware File		|					|
0x0303 - Close Firmware File		|					|
0x0500 - Enter Sleep Mode		|					|
0x0501 - Exit Sleep Mode		|					|
----------------------------------------------------------------------------------------------------------------------------------------------

Sometimes the NMP's hardware will generate Game Pak IRQs on its own. While not exactly commands, these IRQs produce data that can be read in much the same way. That is to say, they'll have a Command ID, Status Data, and SD Card Data if applicable.

----------------------------------------------------------------------------------------------------------------------------------------------
Command	ID				| Parameters				| SD Card Data
----------------------------------------------------------------------------------------------------------------------------------------------
0x8001 - Initialize NMP Hardware	|					|
0x8100 - Update Audio			| Audio Buffer / Trackbar / Timestamp	| Audio Samples
0x8600 - Headphone Status		| Headphone Plugged-In Flag		|
----------------------------------------------------------------------------------------------------------------------------------------------

For any and all ASCII strings sent to or returned by these commands, each character is encoded as a 16-bit MSB value. Each character uses 16-bits. As an example, sending the character "A" for a command parameter involves writing 0x00 to NMP_DATA_IN_LO first, then 0x41 to NMP_DATA_IN_HI later. The overall string is transferred or received from the first character to the last character in order, e.g. the filename "music.mp3" has "m" as the first character and "3" as the final one. Strings must be null terminated as well. Additionally, each string may use extended ASCII encoding. Unlike the original Play-Yan and Play-Yan Micro, the NMP has the font to render extended characters. ID3 tags may also use UTF-16LE encoding as long as the characters are Latin script, however, UTF-8 encoding is not supported.

For each Game Pak IRQ, the first 16-bits of Status Data acts as a sort of "ID" for the command used. Typically, this ID is simply the command itself OR'ed with 0x4000 or 0x8000. Once again, this has parallels to how the Play-Yans operate. When the ID has been OR'ed with 0x4000, this means the NMP is directly responding to a command issued by the software and generating an appropiate Game Pak IRQ. IDs OR'ed with 0x8000, on the other hand, represent Game Pak IRQs generated by the NMP itself.

Below is a list of all known commands along with their parameters, Status Data, and their SD Card Data if applicable.





-----------------------------------------------------------------------
Command 0x0010 - Begin File/Folder List
-----------------------------------------------------------------------
Parameters : N/A
-----------------------------------------------------------------------
Status Data :

Byte 0x0000 - 0x0001	Command ID		0x4010
Byte 0x0002 - 0x0003	End of List Flag	0x0000 or 0x0001
-----------------------------------------------------------------------
SD Card Data:

Byte 0x0000 - 0x020B	File/Folder Name	ASCII String
Byte 0x020C - 0x020D	File/Folder Flag	0x01 = Folder, 0x02 = File
Byte 0x020E - 0x020F	N/A			Unused
-----------------------------------------------------------------------

This command begins reading the names of every file and folder in the current directory of the SD card. The starting location on boot is the SD card's root directory. Unlike the Play-Yans, the NMP reads only 1 file or folder at a time rather than grabbing multiple entires all at once. In order to read the names of all files and folders, the 0x0011 command must be called. For any given directory, the 0x0010 command is only issued once.

The Status Data consists of the Command ID and an End of List Flag. If this flag is non-zero, it means a valid file or folder has been found on the filesystem. If this flag reads zero, that means there are no more files or folders within a directory. As this is the first command called when searching for files and folders, this indicates an empty directory.

The SD Card Data reads 528 bytes in all, with the first 524 being reserved for the file or folder's name. Note, however, that the NMP's software will use far less than that. The next 4 bytes after that dictates whether the entry is a file or a folder. Technically any unsigned value less than or equal to 0x01 represents a folder, and any unsigned value greater than or equal to 0x02 represents a file.





-----------------------------------------------------------------------
Command 0x0011 - Continue File/Folder List
-----------------------------------------------------------------------
Parameters : N/A
-----------------------------------------------------------------------
Status Data :

Byte 0x0000 - 0x0001	Command ID		0x4010
Byte 0x0002 - 0x0003	End of List Flag	0x0000 or 0x0001
-----------------------------------------------------------------------
SD Card Data:

Byte 0x0000 - 0x020B	File/Folder Name	ASCII String
Byte 0x020C - 0x020D	File/Folder Flag	0x01 = Folder, 0x02 = File
Byte 0x020E - 0x020F	N/A			Unused
-----------------------------------------------------------------------

This command continues reading the names of every file and folder in the current directory of the SD card. The starting location on boot is the SD card's root directory. Whereas the 0x0010 is called only once for a given directory, the 0x0011 must be called repeatedly until it detects no more files or folders. This is done by checking the End of List Flag in its Status Data. Otherwise, this command is exactly like its counterpart described above.





-----------------------------------------------------------------------
Command 0x0020 - Change Directory
-----------------------------------------------------------------------
Parameters :

Byte 0x0000 - 0x0209	New Directory		ASCII String
-----------------------------------------------------------------------
Status Data :

Byte 0x0000 - 0x0001	Command ID		0x4020
-----------------------------------------------------------------------
SD Card Data: N/A
-----------------------------------------------------------------------

Changes the current directory that the NMP will use to look for folder or music files. It accepts an ASCII string for the new directory. To go backwards one directory, the string ".." is used.





-----------------------------------------------------------------------
Command 0x0040 - Grab ID3 Data
-----------------------------------------------------------------------
Parameters :

Byte 0x0000 - 0x0209	Music Filename		ASCII String
-----------------------------------------------------------------------
Status Data :

Byte 0x0000 - 0x0001	Command ID		0x4040
Byte 0x0006 - 0x0007	Access Index		0x0101
-----------------------------------------------------------------------
SD Card Data:

Byte 0x0000 - 0x0087	Song Title		ASCII String
Byte 0x0088 - 0x010F	Song Artist		ASCII String
-----------------------------------------------------------------------

Requests the ID3 data for a given MP3 file. It will only return the song's Title and Artist fields. Each field is allotted a total of 68 characters. The NMP's software calls this command before actually playing a file.

This command returns a 16-bit Index in Status Data that must first be accessed before reading the actual data through the SD Card interface. It seems as though the first time this command is called, the software assumes Access Index can be any arbitrary value, however, subsequent commands to grab ID3 data expect the value to be 0x0101.





-----------------------------------------------------------------------
Command 0x0050 - Play Music File
-----------------------------------------------------------------------
Parameters :

Byte 0x0000 - 0x0209	Music Filename		ASCII String
-----------------------------------------------------------------------
Status Data :

Byte 0x0000 - 0x0001	Command ID		0x4050
-----------------------------------------------------------------------
SD Card Data: N/A
-----------------------------------------------------------------------

Begins playback of the specified audio file. This command itself does not deal with audio data, rather, it instructs the hardware to start generating samples. After issuing this command, the NMP will periodically generate additional Game Pak IRQs that have the 0x8100 Command ID and return either audio sample data or updates to the timestamp and trackbar progress.





-----------------------------------------------------------------------
Command 0x0051 - Stop Music Playback
-----------------------------------------------------------------------
Parameters : N/A
-----------------------------------------------------------------------
Status Data :

Byte 0x0000 - 0x0001	Command ID		0x4051
-----------------------------------------------------------------------
SD Card Data: N/A
-----------------------------------------------------------------------

This command halts all music playback and ends all Game Pak IRQs for audio samples or timestamp and trackbar progress. The NMP software returns control of the menu to player so they can navigate the current directory for folders or music files.





-----------------------------------------------------------------------
Command 0x0052 - Pause Music Playback
-----------------------------------------------------------------------
Parameters : N/A
-----------------------------------------------------------------------
Status Data :

Byte 0x0000 - 0x0001	Command ID		0x4052
-----------------------------------------------------------------------
SD Card Data: N/A
-----------------------------------------------------------------------

This command temporarily pauses music playback. Game Pak IRQs for audio samples or timestamp and trackbar progress are put on hold until another command is issued to resume playback.





-----------------------------------------------------------------------
Command 0x0053 - Resume Music Playback
-----------------------------------------------------------------------
Parameters : N/A
-----------------------------------------------------------------------
Status Data :

Byte 0x0000 - 0x0001	Command ID		0x4053
-----------------------------------------------------------------------
SD Card Data: N/A
-----------------------------------------------------------------------

This command resumes music playback after it has been temporarily put on hold. Game Pak IRQs for audio samples or timestamp and trackbar progress will continue after sending this command.





-----------------------------------------------------------------------
Command 0x0060 - Seek Forwards/Backwards
-----------------------------------------------------------------------
Parameters :

Byte 0x0000		Stream Position		0x0000 - 0x0063
Byte 0x0001		Seek Direction
-----------------------------------------------------------------------
Status Data :

Byte 0x0000 - 0x0001	Command ID		0x4060
-----------------------------------------------------------------------
SD Card Data: N/A
-----------------------------------------------------------------------

This command adjusts the current playback position for audio forwards or backwards. The Stream Position parameter represents the current playback position as a percentage (0% to 99%). Seek Direction is an 8-bit value that determines whether the new playback position moves ahead or rewinds. To change the playback position, this command must be called repeatedly (approximately every 15 frames or so) while incremented or decrementing the Seek Direction.

For moving forwards, the initial value of Seek Direction should be 0x00 and increase by 0x10 every time this command is sent. For moving backwards, the initial value of Seek Direction should be 0xF0 and decrease by 0x10 every time this command is sent. The NMP will interpret these changes in Seek Direction and alter the playback position accordingly. Note that since Seek Direction observes 8-bit overflow and underflow. When seeking forward, 0xF0 will roll over into 0x00 on the next command, and when seeking backward, 0x00 will roll over into 0xF0.

Seek Direction is incremented/decremented continuously as long as the user holds down Left or Right on the D-Pad while playing music. It will scale the amount of seconds passed for each instance of the 0x0060 command. The default is 2 seconds, but for every 5 or so instances of the 0x0060 command, another second is added. Due to the way Seek Direction works, the NMP will need to be sent at least 2 0x0060 commands before it actually begins seeking, causing a brief delay when first pressing Left or Right.





-----------------------------------------------------------------------
Command 0x0080 - Adjust Volume
-----------------------------------------------------------------------
Parameters :

Byte 0x0000 - 0x0001	New Volume		0x0000 - 0x002E
-----------------------------------------------------------------------
Status Data :

Byte 0x0000 - 0x0001	Command ID		0x4080
-----------------------------------------------------------------------
SD Card Data: N/A
-----------------------------------------------------------------------

This command adjusts the volume of music playback. The new volume is passed as a parameter, which ranges from 0x00 to 0x2E. Note that this command only affects the volume when using headphones in the cartridge's 3.5mm jack (not the GBA's). It will not change the volume when using any of the GBA for audio output. Users are expected to manually adjust the volume dial/slider on the handheld. A Game Pak IRQ is generated when inserting or removing headphones, which alerts the software on the current headphone status.





-----------------------------------------------------------------------
Command 0x0200 - Play Sound Effect
-----------------------------------------------------------------------
Parameters : N/A
-----------------------------------------------------------------------
Status Data :

Byte 0x0000 - 0x0001	Command ID		0x4200
-----------------------------------------------------------------------
SD Card Data: N/A
-----------------------------------------------------------------------

Plays a sound effect during certain actions, such as selecting menus. The sound effect comes from firmware, just like the Play-Yan models. The NMP hardware will convert the sound effect into samples compatible with the GBA. The 0x0200 command only starts this process; an additional Game Pak IRQ is generated with a Command ID of 0x8100, which supplies the audio data via the SD Card interface.





-----------------------------------------------------------------------
Command 0x0300 - Check For Firmware File
-----------------------------------------------------------------------
Parameters :

Byte 0x0000 - 0x0209	Filename		ASCII String
-----------------------------------------------------------------------
Status Data :

Byte 0x0000 - 0x0001	Command ID		0x4300
Byte 0x0002 - 0x0003	File Exists Flag	0x00 = File Found, 0x01 = No File
-----------------------------------------------------------------------
SD Card Data: N/A
-----------------------------------------------------------------------

This command requests a firmware update file (specifically "meteor.fup") from the SD card if it exists. May be similar to the Check For Key File command on the Play-Yan Micro. If the File Exists Flag from Status Data is zero, the NMP will attempt to open the file and read its contents using additional commands, otherwise it aborts that process immediately.

A total of 522 bytes are used as parameter data, which is simply an ASCII-encoded string for the update file.





-----------------------------------------------------------------------
Command 0x0301 - Read Firmware File
-----------------------------------------------------------------------
Parameters : N/A
-----------------------------------------------------------------------
Status Data :

Byte 0x0000 - 0x0001	Command ID		0x4301
Byte 0x0002 - 0x0003	File Opened Flag	0x00 = Opened, 0x01 = Not Opened
Byte 0x0008 - 0x0009	File Size
-----------------------------------------------------------------------
SD Card Data:

Byte 0x0000 - Size	File Contents
-----------------------------------------------------------------------

This command appears to read the firmware file if it exists. The File Opened Flag determines whether or not the file was successfully opened. If that is the case, the contents of the file are available to read via the SD Card interface. The File Size determines how many bytes should be read from the SD Card. Note that while the File Size can be read as a 32-bit value, the NMP software forcibly masks it to 16-bits.

It appears that if the contents of the firmware update file do not match what the NMP's software expects, it aborts actually trying to load that data into firmware. Although no real firmware update file for the NMP exists, the cartridge's ROM suggests it had a specific header, similar to the firmware updates for the original Play-Yan.





-----------------------------------------------------------------------
Command 0x0303 - Close Firmware File
-----------------------------------------------------------------------
Parameters : N/A
-----------------------------------------------------------------------
Status Data :

Byte 0x0000 - 0x0001	Command ID		0x4303
-----------------------------------------------------------------------
SD Card Data: N/A
-----------------------------------------------------------------------

This command appears to close the firmware file if it was previously opened.




-----------------------------------------------------------------------
Command 0x8001 - Initialize NMP Hardware
-----------------------------------------------------------------------
Parameters : N/A
-----------------------------------------------------------------------
Status Data :

Byte 0x0000 - 0x0001	Command ID		0x8001
-----------------------------------------------------------------------
SD Card Data: N/A
-----------------------------------------------------------------------

After firmware copied from ROM and written to the NMP on boot, the cartridge generates a Game Pak IRQ with this Command ID. The software will wait indefinitely for this IRQ to fire. It will also periodically timeout and attempt to re-upload firmware again. This IRQ signals that the firmware was successful in loading and running on the NMP. As such, it is the very first Game Pak IRQ used after the GBA is turned on.





-----------------------------------------------------------------------
Command 0x8100 - Update Audio
-----------------------------------------------------------------------
Parameters : N/A
-----------------------------------------------------------------------
Status Data :

Byte 0x0000 - 0x0001	Command ID		0x8100
Byte 0x0002 - 0x0003	Audio Buffer Size	0x0000 - 0x0480
Byte 0x0004 - 0x0005	Access Index
Byte 0x0008		Trackbar Position	0x00 - 0x63
Byte 0x000C - 0x000F	Song Timestamp
-----------------------------------------------------------------------
SD Card Data: (The below numbers are an example, assuming Audio Buffer Size = 0x480)

Byte 0x0000 - 0x023F 	Left Audio Buffer
Byte 0x0000 - 0x023F	Right Audio Buffer
-----------------------------------------------------------------------

After issuing either the 0x50 or 0x200 commands, the NMP hardware will begin generating Game Pak IRQs that return audio samples via the SD Card interface (i.e. NMP_DATA_OUT). These IRQs return a lot of Status Data that indicates what is being updated.

The first is a 16-bit value that dictates the Audio Buffer Size in bytes. Its maximum value is 0x0480, and it should also be divisable by 4 (the NMP software forcibly masks it anyway). Typically, while playing a song, the NMP will constantly update audio with an Audio Buffer Size of 0x480, except for the very last samples of a song, which may not evenly be divisable by 0x480 and thus must use a smaller remainer as the size. The second piece of Status Data is a 16-bit value that indicates the Index that must be accessed before any audio samples are read. Unlike the 0x0040 command used to grab ID3 data, the Access Index here is completely arbitrary and determined by the hardware, i.e. it may not always have a fixed value.

Trackbar Position represents current playback position as a percentage. 0% is at the very beginning of a song, 50% is at the exact middle of a song, and 99% is at the very end of a song. Going further actually pushes the trackbar indicator offscreen. As such, this value only accepts an 8-bit value with a range of 0 to 99.

Song Timestamp is the current playback position is seconds. Although it should technically work as 32-bit value, it actually seems to work best as a 24-bit MSB value, using bytes 0x0F, 0x0C, and 0xD in that order. Whereas these bytes add multiple powers of 2 (65536, 256, and 1) to the timestamp, bytes 0x0E adds 1216 seconds to the timestamp.

If the Access Index is zero, that means the cartridge is updating the Trackbar Position and Song Timestamp. In this case, no audio samples are returned. Otherwise, the specified Index is accessed and data is read through the SD Card interface. The data is split into 2 separate buffers, a Left Audio Buffer and Right Audio Buffer. Each buffer is half the length of Audio Buffer Size. For example, when using 0x480 as the Audio Buffer size, the Left Audio Buffer and Right Audio Buffer will each have a length of 0x240 bytes.

Before reading any audio samples, the GBA's CPU must first access the correct index. Afterwards, the sample data becomes available through the SD Card interface. Essentially, the Access Index returned as Status Data represents a virtual address that describes where to grab samples from the NMP. Each address in the Access Index is equal to 16-bits of sample data (a pair of 8-bit samples accessed as a single unit). The first half of this virtual address space is dedicated to the Left Audio Buffer, while the latter half is dedicated to the Right Audio Buffer. For example, if the Audio Buffer Size is 0x480, and the NMP sets the Access Index to 0x200, then the Left Audio Buffer starts at Access Index 0x200, and the Right Audio Buffer starts at Access Index 0x320. Refer to the chart below for more details:

-----------------------------------------------------------------------------------------------------------------------
Index 0x200       | Index 0x201       |  ... ... ... ...   | Index 0x320       | Index 0x321	   |   ... ... ... ...   
-----------------------------------------------------------------------------------------------------------------------
L Samples 000-001 | L Samples 002-003 | L Samples 003-575  | R Samples 000-001 | R Samples 002-003 | R Samples 003-575
-----------------------------------------------------------------------------------------------------------------------

Once the index for either the Left or Right Audio Buffer is accessed, sample data for the entire channel's buffer can be read from the SD Card interface continually until the buffer is full. When switching between channels, however, a new index must be accessed.

Game Pak IRQs with the Command ID 0x8100 are also generated for sound effects. Functionally, there is no difference between the Status Data used for music or sound effects. The NMP software, however, will only play sound effects if no music is currently playing. Obviously, however, the Trackbar Position and Song Timestamp values are unused/irrelevant for sound effects.

When headphones are plugged into the NMP, the cartridge only generates Game Pak IRQs that update the trackbar position. With headphones, audio data is processed by the NMP's own hardware and output separately from the GBA's sound system.





-----------------------------------------------------------------------
Command 0x8600 - Headphone Status
-----------------------------------------------------------------------
Parameters : N/A
-----------------------------------------------------------------------
Status Data :

Byte 0x0000 - 0x0001	Command ID		0x8600
Byte 0x0002 - 0x0003	Headphone Flag		0x00 = No Headphones, 0x01 = Headphones plugged-in
-----------------------------------------------------------------------
SD Card Data: N/A
-----------------------------------------------------------------------

Whenever headphones are inserted or removed from the NMP's 3.5mm jack, a Game Pak IRQ is generated. Additionally, immediately after the NMP hardware has been initialized, the cartridge generates a Game Pak IRQ with this Command ID (ensuring that headphones are detected after booting). The IRQ reports the status of whether headphones are plugged-in/removed, using a single byte in Status Data as a flag. Note that this IRQ is only generated for headphones inside the cartridge itself and is completely unrelated to the GBA's or DS' 3.5mm jack.


***************************************************
8. Firmware Update
***************************************************

The NMP apparently has the ability to update its built-in firmware. After loading the default firmware from ROM, it will search for an update file called "meteor.fup". This functionality is similar to the original Play-Yan that expanded its features (such as MP4 support). Strangely enough, it seems no such firmware update file was ever published by Nintendo. The NMP manual makes no mention of this functionality either. Currently, it remains unknown what sort of upgrades any new firmware might have brought or why Nintendo decided to leave upgrades as a future option. At any rate, it is completely unused at this time.

One interesting detail is that the maximum file size for firmware was supposed to be 65,536 bytes. This is significantly lower than the only known firmware update given for original Play-Yan, which came in around 554KB. The firmware for the NMP was likely far less complicated, perhaps as a result of the hardware lacking any video decoding and focusing exclusively on audio processing.

The firmware update file has to follow some sort of format to be considered valid. The NMP software checks for the presence of the string "Nintendo MP3 Player firmware update program" at the very start of the file's data, much like the original Play-Yan expects of its firmware updates.
