snes_ntsc 0.2.2: SNES NTSC Video Filter
---------------------------------------
Author  : Shay Green <gblargg@gmail.com>
Website : http://www.slack.net/~ant/
Forum   : http://groups.google.com/group/blargg-sound-libs
License : GNU Lesser General Public License (LGPL)
Language: C or C++


Overview
--------
To perform NTSC filtering, first allocate memory for a snes_ntsc_t object
and call snes_ntsc_init(), then call snes_ntsc_blit() to perform
filtering. You can call snes_ntsc_init() at any time to change image
parameters.

By default, snes_ntsc_blit() reads and writes pixels in 16-bit RGB. Edit
snes_ntsc_config.h to change this.


Image Parameters
----------------
Many image parameters can be adjusted and presets are provided for
composite video, S-video, RGB, and monochrome. Most are floating-point
values with a general range of -1.0 to 1.0, where 0 is normal. The
ranges are adjusted so that one parameter at an extreme (-1 or +1) and
the rest at zero shouldn't result in any internal overflow (garbage
pixels). Setting multiple parameters to their extreme can produce
garbage. Put another way, the state space defined by all parameters
within the range -1 to +1 is not fully usable, but some extreme corners
are very useful so I don't want to reduce the parameter ranges.

The sharpness and resolution parameters have similar effects. Resolution
affects how crisp pixels are. Sharpness merely enhances the edges by
increasing contrast, which makes things brighter at the edges. Artifacts
sets how much "junk" is around the edges where colors and brightness
change in the image, where -1 completely eliminates them. (Color) bleed
affects how much colors blend together and the artifact colors at the
edges of pixels surrounded by black. (Color) fringing affects how much
color fringing occurs around the edges of bright objects, especially
white text on a black background.

When using custom settings, initialize your snes_ntsc_setup_t using one
of the standard setups before customizing it. This will ensure that all
fields are properly initialized, including any added in future releases
of the library that your current code can't even know about.

	snes_ntsc_setup_t setup;
	setup = snes_ntsc_composite; /* do this first */
	setup.sharpness = custom_sharpness;
	snes_ntsc_init( ntsc, &setup );


Image Size
----------
For proper aspect ratio, the image generated by the library must be
doubled vertically.

Use the SNES_NTSC_OUT_WIDTH() and SNES_NTSC_IN_WIDTH() macros to convert
between input and output widths that the blitter uses. For example, if
you are blitting an image 256 pixels wide, use SNES_NTSC_OUT_WIDTH( 256 )
to find out how many output pixels are written per row. Another example,
use SNES_NTSC_IN_WIDTH( 640 ) to find how many input pixels will fit
within 640 output pixels. The blitter rounds the input width down in
some cases, so the requested width might not be possible. Use
SNES_NTSC_IN_WIDTH( SNES_NTSC_OUT_WIDTH( in_width ) ) to find what a given
in_width would be rounded down to.


Burst Phase
-----------
The burst_phase parameter to snes_ntsc_blit() should generally toggle
values between frames, i.e. 0 on first call to snes_ntsc_blit(), 1 on
second call, 0 on third call, 1 on fourth, etc. If merge_fields is
enabled (see below), you should always pass 0. Read further for more
detailed operation.

If you're using snes_ntsc_blit() to do partial screen updates,
burst_phase should be calculated as (burst_phase + row) % 3, where row
is the starting row (0 through 239). For example, if burst_phase is 1
for the current frame and you make two calls to snes_ntsc_blit() to blit
rows 0 to 100, then rows 101 to 239, for the first call you should pass
1 for burst_phase, and for the second call you should pass 0 for
burst_phase: (1 + 101) % 3 = 0. Do the same regardless of the
merge_fields setting.


Flickering
----------
The displayed image toggles between two different pixel artifact
patterns at a steady rate, making it appear stable. For an emulator to
duplicate this effect, its frame rate must match the host monitor's
refresh rate, it must be synchronizing to the refresh (vsync), and it
must not be skipping any frames. If any of these don't hold, the image
will probably flicker much more than it would on a TV. It is important
that you play around with these factors to get a good feel for the
issue, and document it clearly for end-users, otherwise they will have
difficulty getting an authentic image.

The library includes a partial workaround for this issue, for the cases
where all the conditions can't be met. When merge_fields is set to 1,
snes_ntsc_blit() does the equivalent of blitting the image twice with the
two different phases and then mixes them together, but without any
performance impact. The result is similar to what you'd see if the
monitor's refresh rate were the same as the emulator's. It does reduce
the shimmer effect when scrolling, so it's not a complete solution to
the refresh rate issue.

The merge_fields option is also useful when taking a screenshot. If you
capture without merge_fields set to 1, you'll only get the even or odd
artifacts, which will make the image look more grainy than when the
emulator is running. Again, play around with this to get an idea of the
difference. It might be best to simply allow the user to choose when to
enable this option.

Note that when you have merge_fields set to 1, you should always pass 0
for the burst_phase parameter to snes_ntsc_blit() (unless doing partial
screen updates). If you don't, you'll still get some flicker.


Custom Blitter
--------------
You can write your own blitter, allowing customization of how input
pixels are obtained, the format of output pixels (15, 16, or 32-bit
RGB), optimizations for your platform, and additional effects like
efficient scanline doubling during blitting.

Macros are included in snes_ntsc.h for writing your blitter so that your
code can be carried over without changes to improved versions of the
library. The default blitter at the end of snes_ntsc.c shows how to use
the macros. Contact me for further assistance.

The SNES_NTSC_BEGIN_ROW macro allows starting up to three pixels. The
first pixel is cut off; its use is in specifying a background color
other than black for the sliver on the left edge. The next two pixels
can be used to handle the extra one or two pixels not handled by the
main chunks of three pixels. For example if you want to blit 257 input
pixels on a row (for whatever odd reason), you would start the first two
with SNES_NTSC_BEGIN_ROW( ... snes_ntsc_black, line_in [0], line_in [1] ),
then do the remaining 255 in chunks of three (255 is divisible by 3).


Limitations
-----------
The library's horizontal rescaling is too wide by about 3% in order to
allow a much more optimal implementation. This means that a 256 pixel
wide input image should appear as 581 output pixels, but with this
library appears as 602 output pixels. TV aspect ratios probably vary by
this much anyway. If you really need unscaled output, contact me and
I'll see about adding it.

Input pixels are converted to 13-bit RGB (4 bits red, 5 bits green, 4
bits blue) to reduce memory usage from 16MB to 4MB. This reduction can
cause slight banding in some smooth gradients. Contact me if you'd like
this reduction made optional.


Thanks
------
Thanks to NewRisingSun for his original code and explanations of NTSC,
which was a starting point for me learning about NTSC video and
decoding. Thanks to the Nesdev forum for feedback and encouragement.
Thanks to Martin Freij (Nestopia author) and Charles MacDonald (SMS Plus
author) for significant ongoing testing and feedback as the library has
improved. Thanks to byuu (bsnes author) and pagefault (ZSNES team) for
feedback about the SNES version.

-- 
Shay Green <gblargg@gmail.com>
