601 lines
41 KiB
HTML
601 lines
41 KiB
HTML
|
|
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
|
|
<meta charset="utf-8" />
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
|
<meta name="generator" content="HelpNDoc Personal Edition 7.9.1.631">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
<link rel="icon" href="favicon.ico"/>
|
|
|
|
<title>NSF Format</title>
|
|
<meta name="description" content="" />
|
|
<meta name="keywords" content="">
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Twitter Card data -->
|
|
<meta name="twitter:card" content="summary">
|
|
<meta name="twitter:title" content="NSF Format">
|
|
<meta name="twitter:description" content="">
|
|
|
|
<!-- Open Graph data -->
|
|
<meta property="og:title" content="NSF Format" />
|
|
<meta property="og:type" content="article" />
|
|
<meta property="og:description" content="" />
|
|
<meta property="og:site_name" content="FCEUX Help" />
|
|
|
|
<!-- Bootstrap core CSS -->
|
|
<link href="vendors/bootstrap-3.4.1/css/bootstrap.min.css" rel="stylesheet"/>
|
|
|
|
<!-- IE10 viewport hack for Surface/desktop Windows 8 bug -->
|
|
<link href="vendors/bootstrap-3.4.1/css/ie10-viewport-bug-workaround.css" rel="stylesheet"/>
|
|
|
|
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
|
|
<!--[if lt IE 9]>
|
|
<script src="vendors/html5shiv-3.7.3/html5shiv.min.js"></script>
|
|
<script src="vendors/respond-1.4.2/respond.min.js"></script>
|
|
<![endif]-->
|
|
|
|
<!-- JsTree styles -->
|
|
<link href="vendors/jstree-3.3.10/themes/default/style.min.css" rel="stylesheet"/>
|
|
|
|
<!-- Hnd styles -->
|
|
<link href="css/layout.min.css" rel="stylesheet" />
|
|
<link href="css/effects.min.css" rel="stylesheet" />
|
|
<link href="css/theme-light-blue.min.css" rel="stylesheet" />
|
|
<link href="css/print.min.css" rel="stylesheet" media="print" />
|
|
<style type="text/css">nav { width: 250px} @media screen and (min-width:769px) { body.md-nav-expanded div#main { margin-left: 250px} body.md-nav-expanded header { padding-left: 264px} }</style>
|
|
<style type="text/css">.navigation #inline-toc { width: auto !important}</style>
|
|
|
|
<!-- Content style -->
|
|
<link href="css/hnd.content.css" rel="stylesheet" />
|
|
|
|
|
|
|
|
|
|
|
|
</head>
|
|
|
|
<body class="md-nav-expanded">
|
|
|
|
|
|
|
|
<div id="skip-link">
|
|
<a href="#main-content" class="element-invisible">Skip to main content</a>
|
|
</div>
|
|
|
|
<header class="headroom">
|
|
<button class="hnd-toggle btn btn-default">
|
|
<span class="sr-only">Toggle navigation</span>
|
|
<span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span>
|
|
</button>
|
|
<h1>FCEUX Help</h1>
|
|
|
|
</header>
|
|
|
|
<nav id="panel-left" class="md-nav-expanded">
|
|
<!-- Nav tabs -->
|
|
<ul class="tab-tabs nav nav-tabs" role="tablist">
|
|
<li id="nav-close">
|
|
<button class="hnd-toggle btn btn-default">
|
|
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span>
|
|
</button>
|
|
</li>
|
|
|
|
|
|
<li role="presentation" class="tab active">
|
|
<a href="#contents" id="tab-contents" aria-controls="contents" role="tab" data-toggle="tab">
|
|
<i class="glyphicon glyphicon-list"></i>
|
|
Contents
|
|
</a>
|
|
</li>
|
|
|
|
<li role="presentation" class="tab">
|
|
<a href="#index" id="tab-index" aria-controls="index" role="tab" data-toggle="tab">
|
|
<i class="glyphicon glyphicon-asterisk"></i>
|
|
Index
|
|
</a>
|
|
</li>
|
|
|
|
<li role="presentation" class="tab">
|
|
<a href="#search" id="tab-search" aria-controls="search" role="tab" data-toggle="tab">
|
|
<i class="glyphicon glyphicon-search"></i>
|
|
Search
|
|
</a>
|
|
</li>
|
|
|
|
</ul> <!-- /Nav tabs -->
|
|
|
|
<!-- Tab panes -->
|
|
<div class="tab-content">
|
|
|
|
<div role="tabpanel" class="tab-pane active" id="contents">
|
|
<div id="toc" class="tree-container unselectable"
|
|
data-url="_toc.json"
|
|
data-openlvl="1"
|
|
>
|
|
|
|
</div>
|
|
</div> <!-- /contents-->
|
|
|
|
<div role="tabpanel" class="tab-pane" id="index">
|
|
<div id="keywords" class="tree-container unselectable"
|
|
data-url="_keywords.json"
|
|
data-openlvl="1"
|
|
>
|
|
|
|
</div>
|
|
</div> <!-- /index-->
|
|
|
|
<div role="tabpanel" class="tab-pane" id="search">
|
|
<div class="search-content">
|
|
<div class="search-input">
|
|
<form id="search-form">
|
|
<div class="form-group">
|
|
<div class="input-group">
|
|
<input type="text" class="form-control" id="input-search" name="input-search" placeholder="Search..." />
|
|
<span class="input-group-btn">
|
|
<button class="btn btn-default" type="submit">
|
|
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
|
|
</button>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div> <!-- /search-input -->
|
|
<div class="search-result">
|
|
<div id="search-info"></div>
|
|
<div class="tree-container unselectable" id="search-tree"></div>
|
|
</div> <!-- /search-result -->
|
|
</div> <!-- /search-content -->
|
|
</div> <!-- /search-->
|
|
|
|
</div> <!-- /Tab panes -->
|
|
|
|
</nav>
|
|
|
|
<div id="main">
|
|
|
|
<article>
|
|
<div id="topic-content" class="container-fluid"
|
|
data-hnd-id="NSFFormat"
|
|
data-hnd-context="29"
|
|
data-hnd-title="NSF Format"
|
|
>
|
|
|
|
<div class="navigation">
|
|
<ol class="breadcrumb">
|
|
<li><a href="Technicalinformation.html">Technical Information</a></li><li><a href="Sound.html">Sound</a></li>
|
|
</ol>
|
|
<div class="nav-arrows">
|
|
<div class="btn-group btn-group" role="group"><a class="btn btn-default" href="Sound.html" title="Sound" role="button"><span class="glyphicon glyphicon-menu-up" aria-hidden="true"></span></a><a class="btn btn-default" href="Sound.html" title="Sound" role="button"><span class="glyphicon glyphicon-menu-left" aria-hidden="true"></span></a><a class="btn btn-default" href="NESSound.html" title="NES Sound" role="button"><span class="glyphicon glyphicon-menu-right" aria-hidden="true"></span></a></div>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<a id="main-content"></a>
|
|
|
|
<h2>NSF Format</h2>
|
|
|
|
<div class="main-content">
|
|
|
|
<p class="rvps2"><span class="rvts41">NES Music Format Spec</span></p>
|
|
<p class="rvps2"><span class="rvts6"> ---------------------</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">By: Kevin Horton khorton@iquest.net</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">NOTE:</span></p>
|
|
<p class="rvps2"><span class="rvts6">-----</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Remember that I am very willing to add stuff and update this spec. If</span></p>
|
|
<p class="rvps2"><span class="rvts6">you find a new sound chip or other change let me know and I will get back</span></p>
|
|
<p class="rvps2"><span class="rvts6">with you. E-mail to the above address. </span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">V1.61 - 06/27/2000 Updated spec a bit</span></p>
|
|
<p class="rvps2"><span class="rvts6">V1.60 - 06/01/2000 Updated Sunsoft, MMC5, and Namco chip information</span></p>
|
|
<p class="rvps2"><span class="rvts6">V1.50 - 05/28/2000 Updated FDS, added Sunsoft and Namco chips</span></p>
|
|
<p class="rvps2"><span class="rvts6">V1.32 - 11/27/1999 Added MMC5 register locations</span></p>
|
|
<p class="rvps2"><span class="rvts6">V1.30 - 11/14/1999 Added MMC5 audio bit, added some register info</span></p>
|
|
<p class="rvps2"><span class="rvts6">V1.20 - 09/12/1999 VRC and FDS prelim sound info added</span></p>
|
|
<p class="rvps2"><span class="rvts6">V1.00 - 05/11/1999 First official NSF specification file</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">This file encompasses a way to transfer NES music data in a small, easy to</span></p>
|
|
<p class="rvps2"><span class="rvts6">use format.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">The basic idea is one rips the music/sound code from an NES game and prepends</span></p>
|
|
<p class="rvps2"><span class="rvts6">a small header to the data.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">A program of some form (6502/sound emulator) then takes the data and loads</span></p>
|
|
<p class="rvps2"><span class="rvts6">it into the proper place into the 6502's address space, then inits and plays</span></p>
|
|
<p class="rvps2"><span class="rvts6">the tune.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Here's an overview of the header:</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">offset # of bytes Function</span></p>
|
|
<p class="rvps2"><span class="rvts6">----------------------------</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">0000 5 STRING "NESM",01Ah ; denotes an NES sound format file</span></p>
|
|
<p class="rvps2"><span class="rvts6">0005 1 BYTE Version number (currently 01h)</span></p>
|
|
<p class="rvps2"><span class="rvts6">0006 1 BYTE Total songs (1=1 song, 2=2 songs, etc)</span></p>
|
|
<p class="rvps2"><span class="rvts6">0007 1 BYTE Starting song (1= 1st song, 2=2nd song, etc)</span></p>
|
|
<p class="rvps2"><span class="rvts6">0008 2 WORD (lo/hi) load address of data (8000-FFFF)</span></p>
|
|
<p class="rvps2"><span class="rvts6">000a 2 WORD (lo/hi) init address of data (8000-FFFF)</span></p>
|
|
<p class="rvps2"><span class="rvts6">000c 2 WORD (lo/hi) play address of data (8000-FFFF)</span></p>
|
|
<p class="rvps2"><span class="rvts6">000e 32 STRING The name of the song, null terminated</span></p>
|
|
<p class="rvps2"><span class="rvts6">002e 32 STRING The artist, if known, null terminated</span></p>
|
|
<p class="rvps2"><span class="rvts6">004e 32 STRING The Copyright holder, null terminated</span></p>
|
|
<p class="rvps2"><span class="rvts6">006e 2 WORD (lo/hi) speed, in 1/1000000th sec ticks, NTSC (see text)</span></p>
|
|
<p class="rvps2"><span class="rvts6">0070 8 BYTE Bankswitch Init Values (see text, and FDS section)</span></p>
|
|
<p class="rvps2"><span class="rvts6">0078 2 WORD (lo/hi) speed, in 1/1000000th sec ticks, PAL (see text)</span></p>
|
|
<p class="rvps2"><span class="rvts6">007a 1 BYTE PAL/NTSC bits:</span></p>
|
|
<p class="rvps2"><span class="rvts6"> bit 0: if clear, this is an NTSC tune</span></p>
|
|
<p class="rvps2"><span class="rvts6"> bit 0: if set, this is a PAL tune</span></p>
|
|
<p class="rvps2"><span class="rvts6"> bit 1: if set, this is a dual PAL/NTSC tune</span></p>
|
|
<p class="rvps2"><span class="rvts6"> bits 2-7: not used. they *must* be 0</span></p>
|
|
<p class="rvps2"><span class="rvts6">007b 1 BYTE Extra Sound Chip Support</span></p>
|
|
<p class="rvps2"><span class="rvts6"> bit 0: if set, this song uses VRCVI</span></p>
|
|
<p class="rvps2"><span class="rvts6"> bit 1: if set, this song uses VRCVII</span></p>
|
|
<p class="rvps2"><span class="rvts6"> bit 2: if set, this song uses FDS Sound</span></p>
|
|
<p class="rvps2"><span class="rvts6"> bit 3: if set, this song uses MMC5 audio</span></p>
|
|
<p class="rvps2"><span class="rvts6"> bit 4: if set, this song uses Namco 106</span></p>
|
|
<p class="rvps2"><span class="rvts6"> bit 5: if set, this song uses Sunsoft FME-07</span></p>
|
|
<p class="rvps2"><span class="rvts6"> bits 6,7: future expansion: they *must* be 0</span></p>
|
|
<p class="rvps2"><span class="rvts6">007c 4 ---- 4 extra bytes for expansion (must be 00h)</span></p>
|
|
<p class="rvps2"><span class="rvts6">0080 nnn ---- The music program/data follows</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">This may look somewhat familiar; if so that's because this is somewhat</span></p>
|
|
<p class="rvps2"><span class="rvts6">sorta of based on the PSID file format for C64 music/sound.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Loading a tune into RAM</span></p>
|
|
<p class="rvps2"><span class="rvts6">-----------------------</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">If offsets 0070h to 0077h have 00h in them, then bankswitching is *not*</span></p>
|
|
<p class="rvps2"><span class="rvts6">used. If one or more bytes are something other than 00h then bankswitching</span></p>
|
|
<p class="rvps2"><span class="rvts6">is used. If bankswitching is used then the load address is still used,</span></p>
|
|
<p class="rvps2"><span class="rvts6">but you now use (ADDRESS AND 0FFFh) to determine where on the first bank</span></p>
|
|
<p class="rvps2"><span class="rvts6">to load the data.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Each bank is 4K in size, and that means there are 8 of them for the</span></p>
|
|
<p class="rvps2"><span class="rvts6">entire 08000h-0ffffh range in the 6502's address space. You determine where</span></p>
|
|
<p class="rvps2"><span class="rvts6">in memory the data goes by setting bytes 070h thru 077h in the file.</span></p>
|
|
<p class="rvps2"><span class="rvts6">These determine the inital bank values that will be used, and hence where</span></p>
|
|
<p class="rvps2"><span class="rvts6">the data will be loaded into the address space.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Here's an example:</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">METROID.NSF will be used for the following explaination.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">The file is set up like so: (starting at 070h in the file)</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">0070: 05 05 05 05 05 05 05 05 - 00 00 00 00 00 00 00 00</span></p>
|
|
<p class="rvps2"><span class="rvts6">0080: ... music data goes here...</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Since 0070h-0077h are something other than 00h, then we know that this</span></p>
|
|
<p class="rvps2"><span class="rvts6">tune uses bankswitching. The load address for the data is specified as</span></p>
|
|
<p class="rvps2"><span class="rvts6">08000h. We take this AND 0fffh and get 0000h, so we will load data in</span></p>
|
|
<p class="rvps2"><span class="rvts6">at byte 0 of bank 0, since data is loaded into the banks sequentially</span></p>
|
|
<p class="rvps2"><span class="rvts6">starting from bank 0 up until the music data is fully loaded.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Metroid has 6 4K banks in it, numbered 0 through 5. The 6502's address</span></p>
|
|
<p class="rvps2"><span class="rvts6">space has 8 4K bankswitchable blocks on it, starting at 08000h-08fffh,</span></p>
|
|
<p class="rvps2"><span class="rvts6">09000h-09fffh, 0a000h-0afffh ... 0f000h-0ffffh. Each one of these is 4K in</span></p>
|
|
<p class="rvps2"><span class="rvts6">size, and the current bank is controlled by writes to 05ff8h thru 05fffh,</span></p>
|
|
<p class="rvps2"><span class="rvts6">one byte per bank. So, 05ff8h controls the 08000h-08fffh range, 05ff9h </span></p>
|
|
<p class="rvps2"><span class="rvts6">controls the 09000h-09fffh range, etc. up to 05fffh which controls the </span></p>
|
|
<p class="rvps2"><span class="rvts6">0f000h-0ffffh range. When the song is loaded into RAM, it is loaded into</span></p>
|
|
<p class="rvps2"><span class="rvts6">the banks and not the 6502's address space. Once this is done, then the</span></p>
|
|
<p class="rvps2"><span class="rvts6">bank control registers are written to set up the inital bank values.</span></p>
|
|
<p class="rvps2"><span class="rvts6">To do this, the value at 0070h in the file is written to 05ff8h, 0071h</span></p>
|
|
<p class="rvps2"><span class="rvts6">is written to 05ff9h, etc. all the way to 0077h is written to 05fffh.</span></p>
|
|
<p class="rvps2"><span class="rvts6">This is should be done before every call to the init routine.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">If the tune was not bankswitched, then it is simply loaded in at the </span></p>
|
|
<p class="rvps2"><span class="rvts6">specified load address, until EOF</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Initalizing a tune</span></p>
|
|
<p class="rvps2"><span class="rvts6">------------------</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">This is pretty simple. Load the desired song # into the accumulator,</span></p>
|
|
<p class="rvps2"><span class="rvts6">minus 1 and set the X register to specify PAL (X=1) or NTSC (X=0).</span></p>
|
|
<p class="rvps2"><span class="rvts6">If this is a single standard tune (i.e. PAL *or* NTSC but not both)</span></p>
|
|
<p class="rvps2"><span class="rvts6">then the X register contents should not matter. Once the song # and</span></p>
|
|
<p class="rvps2"><span class="rvts6">optional PAL/NTSC standard are loaded, simply call the INIT address.</span></p>
|
|
<p class="rvps2"><span class="rvts6">Once init is done, it should perform an RTS.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Playing a tune</span></p>
|
|
<p class="rvps2"><span class="rvts6">--------------</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Once the tune has been initalized, it can now be played. To do this,</span></p>
|
|
<p class="rvps2"><span class="rvts6">simply call the play address several times a second. How many times</span></p>
|
|
<p class="rvps2"><span class="rvts6">per second is determined by offsets 006eh and 006fh in the file.</span></p>
|
|
<p class="rvps2"><span class="rvts6">These bytes denote the speed of playback in 1/1000000ths of a second. </span></p>
|
|
<p class="rvps2"><span class="rvts6">For the "usual" 60Hz playback rate, set this to 411ah. </span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">To generate a differing playback rate, use this formula:</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"> 1000000</span></p>
|
|
<p class="rvps2"><span class="rvts6">PBRATE= ---------</span></p>
|
|
<p class="rvps2"><span class="rvts6"> speed</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Where PBRATE is the value you stick into 006e/006fh in the file, and</span></p>
|
|
<p class="rvps2"><span class="rvts6">speed is the desired speed in hertz. </span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">"Proper" way to load the tune</span></p>
|
|
<p class="rvps2"><span class="rvts6">-----------------------------</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">1) If the tune is bankswitched, go to #3.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">2) Load the data into the 6502's address space starting at the specified</span></p>
|
|
<p class="rvps2"><span class="rvts6"> load address. Go to #4.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">3) Load the data into a RAM area, starting at (start_address AND 0fffh).</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">4) Tune load is done.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">"Proper" way to init a tune</span></p>
|
|
<p class="rvps2"><span class="rvts6">---------------------------</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">1) Clear all RAM at 0000h-07ffh.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">2) Clear all RAM at 6000h-7fffh.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">3) Init the sound registers by writing 00h to 04000-0400Fh, 10h to 4010h,</span></p>
|
|
<p class="rvps2"><span class="rvts6"> and 00h to 4011h-4013h.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">4) Set volume register 04015h to 00fh.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">5) If this is a banked tune, load the bank values from the header into</span></p>
|
|
<p class="rvps2"><span class="rvts6"> 5ff8-5fffh.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">6) Set the accumulator and X registers for the desired song.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">7) Call the music init routine.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">"Proper" way to play a tune</span></p>
|
|
<p class="rvps2"><span class="rvts6">---------------------------</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">1) Call the play address of the music at periodic intervals determined</span></p>
|
|
<p class="rvps2"><span class="rvts6"> by the speed words. Which word to use is determined by which mode</span></p>
|
|
<p class="rvps2"><span class="rvts6"> you are in- PAL or NTSC.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Sound Chip Support</span></p>
|
|
<p class="rvps2"><span class="rvts6">------------------</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Byte 007bh of the file stores the sound chip flags. If a particular flag</span></p>
|
|
<p class="rvps2"><span class="rvts6">is set, those sound registers should be enabled. If the flag is clear,</span></p>
|
|
<p class="rvps2"><span class="rvts6">then those registers should be disabled.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">* VRCVI Uses registers 9000-9002, A000-A002, and B000-B002, write only.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Caveats: 1) The above registers are *write only* and must not disrupt music</span></p>
|
|
<p class="rvps2"><span class="rvts6"> code that happens to be stored there.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"> 2) Major caveat: The A0 and A1 lines are flipped on a few games!!</span></p>
|
|
<p class="rvps2"><span class="rvts6"> If you rip the music and it sounds all funny, flip around </span></p>
|
|
<p class="rvps2"><span class="rvts6"> the xxx1 and xxx2 register pairs. (i.e. 9001 and 9002) 9000</span></p>
|
|
<p class="rvps2"><span class="rvts6"> and 9003 can be left untouched. I decided to do this since it </span></p>
|
|
<p class="rvps2"><span class="rvts6"> would make things easier all around, and this means you only </span></p>
|
|
<p class="rvps2"><span class="rvts6"> will have to change the music code in a very few places (6).</span></p>
|
|
<p class="rvps2"><span class="rvts6"> Esper2 and Madara will need this change, while Castlevania 3j</span></p>
|
|
<p class="rvps2"><span class="rvts6"> will not for instance.</span></p>
|
|
<p class="rvps2"><span class="rvts6"> </span></p>
|
|
<p class="rvps2"><span class="rvts6"> 3) See my VRCVI.TXT doc for a complete register description.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">* VRCVII Uses registers 9010 and 9030, write only.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Caveats: 1) Same caveat as #1, above.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"> 2) See my VRCVII.TXT doc for a complete register description.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">* FDS Sound uses registers from 4040 through 4092.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Caveats: 1) 6000-DFFF is assumed to be RAM, since 6000-DFFF is RAM on the</span></p>
|
|
<p class="rvps2"><span class="rvts6"> FDS. E000-FFFF is usually not included in FDS games because</span></p>
|
|
<p class="rvps2"><span class="rvts6"> it is the BIOS ROM. However, it can be used on FDS rips to help</span></p>
|
|
<p class="rvps2"><span class="rvts6"> the ripper (for modified play/init addresses).</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"> 2) Bankswitching operates slightly different on FDS tunes. </span></p>
|
|
<p class="rvps2"><span class="rvts6"> 5FF6 and 5FF7 control the banks 6000-6FFF and 7000-7FFF </span></p>
|
|
<p class="rvps2"><span class="rvts6"> respectively. NSF header offsets 76h and 77h correspond to</span></p>
|
|
<p class="rvps2"><span class="rvts6"> *both* 6000-7FFF *AND* E000-FFFF. Keep this in mind!</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">* MMC5 Sound Uses registers 5000-5015, write only as well as 5205 and 5206,</span></p>
|
|
<p class="rvps2"><span class="rvts6"> and 5C00-5FF5</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Caveats: 1) Generating a proper doc file. Be patient. </span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"> 2) 5205 and 5206 are a hardware 8*8 multiplier. The idea being</span></p>
|
|
<p class="rvps2"><span class="rvts6"> you write your two bytes to be multiplied into 5205 and 5206</span></p>
|
|
<p class="rvps2"><span class="rvts6"> and after doing so, you read the result back out. Still working</span></p>
|
|
<p class="rvps2"><span class="rvts6"> on what exactly triggers it (I think a write to either 5205</span></p>
|
|
<p class="rvps2"><span class="rvts6"> or 5206 triggers the multiply).</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"> 3) 5C00-5FF5 should be RAM to emulate EXRAM while in MMC5 mode.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Note: Thanks to Mamiya for the EXRAM info.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">* Namco 106 Sound Uses registers 4800 and F800. </span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"> This works similar to VRC7. 4800 is the "data" port which is</span></p>
|
|
<p class="rvps2"><span class="rvts6"> readable and writable, while F800 is the "address" port and is</span></p>
|
|
<p class="rvps2"><span class="rvts6"> writable only.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"> The address is 7 bits plus a "mode" bit. Bit 7 controls</span></p>
|
|
<p class="rvps2"><span class="rvts6"> address auto-incrementing. If bit 7 is set, the address will</span></p>
|
|
<p class="rvps2"><span class="rvts6"> auto-increment after a byte of data is read or written from/to</span></p>
|
|
<p class="rvps2"><span class="rvts6"> 4800.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"> $40 ffffffff f:frequency L</span></p>
|
|
<p class="rvps2"><span class="rvts6"> $42 ffffffff f:frequency M</span></p>
|
|
<p class="rvps2"><span class="rvts6"> $44 ---sssff f:frequency H s:tone length (8-s)*4 in 4bit-samples</span></p>
|
|
<p class="rvps2"><span class="rvts6"> $46 tttttttt t:tone address(4bit-address,$41 means high-4bits of $20)</span></p>
|
|
<p class="rvps2"><span class="rvts6"> $47 -cccvvvv v:linear volume 1+c:number of channels in use($7F only)</span></p>
|
|
<p class="rvps2"><span class="rvts6"> $40-47:ch1 $48-4F:ch2 ... $78-7F:ch8</span></p>
|
|
<p class="rvps2"><span class="rvts6"> ch2-ch8 same to ch1</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"> $00-3F(8ch)...77(1ch) hhhhllll tone data</span></p>
|
|
<p class="rvps2"><span class="rvts6"> h:odd address data(signed 4bit)</span></p>
|
|
<p class="rvps2"><span class="rvts6"> l:even address data(signed 4bit)</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"> real frequency = (f * NES_BASECYCLES) / (40000h * (c+1) * (8-s)*4 * 45)</span></p>
|
|
<p class="rvps2"><span class="rvts6"> NES_BASECYCLES 21477270(Hz)</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Note: Very Special thanks to Mamiya for this information!</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">* Sunsoft FME-07 Sound uses registers C000 and E000</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"> This is similar to the common AY 3-8910 sound chip that is</span></p>
|
|
<p class="rvps2"><span class="rvts6"> used on tons of arcade machines, and in the Intellivision.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"> C000 is the address port</span></p>
|
|
<p class="rvps2"><span class="rvts6"> E000 is the data port</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"> Both are write-only, and behave like the AY 3-8910.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Note: Special thanks to Mamiya for this information as well</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">Caveats</span></p>
|
|
<p class="rvps2"><span class="rvts6">-------</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">1) The starting song number and maximum song numbers start counting at</span></p>
|
|
<p class="rvps2"><span class="rvts6"> 1, while the init address of the tune starts counting at 0. To</span></p>
|
|
<p class="rvps2"><span class="rvts6"> "fix", simply pass the desired song number minus 1 to the init</span></p>
|
|
<p class="rvps2"><span class="rvts6"> routine.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">2) The NTSC speed word is used *only* for NTSC tunes, or dual PAL/NTSC tunes.</span></p>
|
|
<p class="rvps2"><span class="rvts6"> The PAL speed word is used *only* for PAL tunes, or dual PAL/NTSC tunes.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">3) The length of the text in the name, artist, and copyright fields must </span></p>
|
|
<p class="rvps2"><span class="rvts6"> be 31 characters or less! There has to be at least a single NULL byte</span></p>
|
|
<p class="rvps2"><span class="rvts6"> (00h) after the text, between fields.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">4) If a field is not known (name, artist, copyright) then the field must</span></p>
|
|
<p class="rvps2"><span class="rvts6"> contain the string "<?>" (without quotes). </span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">5) There should be 8K of RAM present at 6000-7FFFh. MMC5 tunes need RAM at</span></p>
|
|
<p class="rvps2"><span class="rvts6"> 5C00-5FF7 to emulate its EXRAM. 8000-FFFF Should be read-only (not </span></p>
|
|
<p class="rvps2"><span class="rvts6"> writable) after a tune has loaded. The only time this area should be </span></p>
|
|
<p class="rvps2"><span class="rvts6"> writable is if an FDS tune is being played.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">6) Do not assume the state of *anything* on entry to the init routine</span></p>
|
|
<p class="rvps2"><span class="rvts6"> except A and X. Y can be anything, as can the flags. </span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">7) Do not assume the state of *anything* on entry to the play routine either.</span></p>
|
|
<p class="rvps2"><span class="rvts6"> Flags, X, A, and Y could be at any state. I've fixed about 10 tunes</span></p>
|
|
<p class="rvps2"><span class="rvts6"> because of this problem and the problem, above.</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">8) The stack sits at 1FFh and grows down. Make sure the tune does not</span></p>
|
|
<p class="rvps2"><span class="rvts6"> attempt to use 1F0h-1FFh for variables. (Armed Dragon Villigust did and</span></p>
|
|
<p class="rvps2"><span class="rvts6"> I had to relocate its RAM usage to 2xx)</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">9) Variables should sit in the 0000h-07FFh area *only*. If the tune writes</span></p>
|
|
<p class="rvps2"><span class="rvts6"> outside this range, say 1400h this is bad and should be relocated. </span></p>
|
|
<p class="rvps2"><span class="rvts6"> (Terminator 3 did this and I relocated it to 04xx).</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6">That's it!</span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"><br/></span></p>
|
|
<p class="rvps2"><span class="rvts6"></span><span class="rvts6"></span></p>
|
|
<p class="rvps4" style="clear: both;"><span class="rvts18">Created with the Personal Edition of HelpNDoc: </span><a class="rvts19" href="https://www.helpndoc.com/feature-tour">Full-featured Help generator</a></p>
|
|
|
|
</div>
|
|
|
|
<div id="topic_footer"><div id="topic_footer_content">2020</div></div>
|
|
</div> <!-- /#topic-content -->
|
|
</article>
|
|
|
|
<footer></footer>
|
|
|
|
</div> <!-- /#main -->
|
|
|
|
<div class="mask" data-toggle="sm-nav-expanded"></div>
|
|
|
|
<!-- Modal -->
|
|
<div class="modal fade" id="hndModal" tabindex="-1" role="dialog" aria-labelledby="hndModalLabel">
|
|
<div class="modal-dialog" role="document">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
|
<h4 class="modal-title" id="hndModalLabel"></h4>
|
|
</div>
|
|
<div class="modal-body">
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-primary modal-btn-close" data-dismiss="modal">Close</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Splitter -->
|
|
<div id="hnd-splitter" style="left: 250px"></div>
|
|
|
|
<!-- Scripts -->
|
|
<script src="vendors/jquery-3.5.1/jquery.min.js"></script>
|
|
<script src="vendors/bootstrap-3.4.1/js/bootstrap.min.js"></script>
|
|
<script src="vendors/bootstrap-3.4.1/js/ie10-viewport-bug-workaround.js"></script>
|
|
<script src="vendors/markjs-8.11.1/jquery.mark.min.js"></script>
|
|
<script src="vendors/uri-1.19.2/uri.min.js"></script>
|
|
<script src="vendors/imageMapResizer-1.0.10/imageMapResizer.min.js"></script>
|
|
<script src="vendors/headroom-0.11.0/headroom.min.js"></script>
|
|
<script src="vendors/jstree-3.3.10/jstree.min.js"></script>
|
|
<script src="vendors/interactjs-1.9.22/interact.min.js"></script>
|
|
|
|
<!-- HelpNDoc scripts -->
|
|
<script src="js/polyfill.object.min.js"></script>
|
|
<script src="_translations.js"></script>
|
|
<script src="js/hndsd.min.js"></script>
|
|
<script src="js/hndse.min.js"></script>
|
|
<script src="js/app.min.js"></script>
|
|
|
|
<!-- Init script -->
|
|
<script>
|
|
$(function() {
|
|
// Create the app
|
|
var app = new Hnd.App({
|
|
searchEngineMinChars: 3
|
|
});
|
|
// Update translations
|
|
hnd_ut(app);
|
|
// Instanciate imageMapResizer
|
|
imageMapResize();
|
|
// Custom JS
|
|
|
|
// Boot the app
|
|
app.Boot();
|
|
});
|
|
</script>
|
|
|
|
|
|
|
|
</body>
|
|
|
|
</html>
|
|
|