Nes_Snd_Emu Notes


DMC memory access
-----------------

The APU's DMC plays samples from memory, so it needs access to the emulated
memory space. Be sure to set the DMC's memory reader callback function with
Nes_Apu::dmc_reader().


Blip_Buffer operation
---------------------

The demo shows basic Blip_Buffer use. For more information and examples of
using Blip_Buffer, download the full Blip_Buffer library package from
http://www.slack.net/~ant/libs/


Sound chip accuracy
-------------------

The non-linear interaction between the triangle, noise, and DMC oscillators as
described in the NES APU Reference isn't implemented. I haven't yet come up
with an elegant way to handle it.


Expansion hardware
------------------

I have written emulators for Namco N106 and Konami VRC6 sound chips but haven't
put them with the archive. They have a the same style interface as Nes_Apu.
Contact me if you'd like them added.


Time frames
-----------

Synthesis is usually of greater duration than the length of the sample buffer
and limited range of the time type. Because of this, synthesis can be broken
into individual frames with time specified relative to the beginning of the
frame.

A frame of sound is made with Blip_Buffer by adding transitions and ended by
specifying its duration to end_frame(); this begins a new frame after the old
one.

The resulting samples of previous frames can be read out of the buffer with
read_samples(). Once read the samples are removed. Unread samples reduce buffer
space available to the current frame.

Time frames can be any length, so long as they fit into the buffer. Successive
time frames don't need to be the same length; each time frame can be a
different length.


Output sample rate
------------------

The library works best with an output sample rate around 44-48 kHz. Because the
output is band-limited, there is little reason to use a higher sampling rate
(i.e. 96 kHz) unless it benefits the output hardware.


Problems due to compiler's optimizer
------------------------------------

If you are having problems with the library first try lowering or turning off
the compiler's optimizer. If this fixes the problem, contact me so I can add a
workaround in the next version.


Limited Blip_Buffer length
--------------------------

A Blip_Buffer can't be larger than approximately 65000 samples. At a 44100
sample rate, the length is limited to 1500 milliseconds. This is unlikely to be
a problem since synthesis is usually done in much smaller time segments.


Thread-safety
-------------

When using multiple threads, except where noted you must ensure that only one
thread invokes a function at a time; the library is not written to handle
concurrent operations. Most functions fall into either one-time setup or
ongoing operations, so this won't be much of an issue.


Treble equalization (low-pass filtering)
----------------------------------------

Blip_Synth and Blip_Wave have flexible high-frequency equalization to allow
matching the characteristics of sound hardware. The blip_eq_t type stores the
parameters.

A blip_eq_t( treble ) specifies an exponential rolloff beginning at 0 Hz and
attenuating by 'treble' dB at half the sample rate. For example, with treble =
-12 dB, the following results:

  0dB ---___  
            ~~~---___
	                 ~~~---___
	                          ~~~---___
	                                   ~~~---_* treble = -12dB
	                                   
-18dB - - - - - - - - - - - - - - - - - - - - - 
	  0                                sample rate / 2


A blip_eq_t( treble, cutoff, sample_rate ) specifies an exponential rolloff
beginning at 'cutoff' Hz and attenuating by 'treble' dB at 22kHz. For example,
with cutoff = 8000 Hz and treble = -6 dB, the following results:

        cutoff = 8kHz
  0dB -------*__                
	            ~~--__ treble = -6dB
	                  ~~-*__
	                        ~~--__
	                              ~~--__
	                                    ~~--__
-18dB - - - - - - - - - - - - - - - - - - - - - -
	  0      8kHz      22kHz               44kHz ...



Bass frequency (high-pass filtering)
------------------------------------

Blip_Buffer::bass_freq( breakpoint ) results in a steep rolloff which passes
-3dB attenuation at 'breakpoint' Hz. For example, with breakpoint = 1000 Hz,
the following results:

      breakpoint = 1000 Hz
 0dB                 ___________
-3dB      ,_*---~~~~~       
        _~
       /
	  /
      |
      |
-21dB - - - - - - - - - - - - -
	  0   1000 Hz            4000 Hz

The primary purpose of Blip_Buffer::bass_freq() is to remove any DC component
(an unchanging offset from center level) from the output since it would reduce
the available volume range. The default value of 15 Hz works well in general.
The breakpoint can be increased to simulate a smaller speaker (like on a
GameBoy). Since DC removal can hide erroneous Blip_Synth-based oscillators
which drift, it can be useful to disable low-pass filtering by setting the
breakpoint to 0 Hz and examine the output with a sound program. Blip_Wave
oscillators are immune since they deal in absolute amplitudes rather than
differences.


Compatibility/Performance
-------------------------

Little compatibility checking and performance tuning have been done for common
platforms. Any assistance in this would be appreciated. If you have *any*
trouble or come up with improvements, contact me.


Configuration
-------------

The header "blargg_common.h" is used to establish a common environment. It
attempts to automatically determine the features of the environment, but might
need assistance.

If HAVE_CONFIG_H is defined, the file "config.h" is included at the beginning
of each library header file, allowing configuration options for the library to
be set. It's fine if other libraries also use this scheme, as they won't
conflict.

Some libraries depend on the byte ordering of multibyte types. If this can't be
determined and the library requires it, a compilation error will result. For
big-endian (most significant byte first, i.e. Motorola 68000, PowerPC), #define
BLARGG_BIG_ENDIAN to 1. For little-endian (least significant byte first, i.e.
Intel x86), #define BLARGG_LITTLE_ENDIAN to 1.

Pre-ISO C++ compilers might not support bool. Support is provided where bool is
not available, but the compiler's support of bool might not be properly
determined. If errors occur in "blargg_common.h" in the bool section, #define
BLARGG_COMPILER_HAS_BOOL to 1 or 0 depending on whether your compiler supports
bool or not.

If you have any problems with "blargg_common.h", contact me.


Boost Compatibility
-------------------

Boost is a collection of useful libraries which provide basic services. If it's
not installed in your environment or your environment isn't supported, a small
substitute is included in the "boost/" directory. This substitute implements a
small subset of boost in a way that will work with most compilers. If boost is
already installed, delete the included "boost/" directory. For more information
about boost, see http://boost.org/


Error handling
--------------

To allow compatibility with older (ARM) C++ compilers, no exceptions are thrown
by any of the libraries. The library is exception-safe, and any exceptions
which occur are not intercepted.

Memory allocation is kept to an absolute minimum. If the C++ compiler's memory
allocator throws an exception when no more memory is available, this will be
allowed to propagate, otherwise if no exceptions are used a lack of memory will
be reported via the return value.

Significant violations of the documented interface are flagged with debug-only
assertions. Failure of these usually indicates a caller error rather than a
defect in the library.


Support for 16-bit ints
-----------------------

Some compilers for smaller architectures use 16-bits for the 'int' type because
it improves performance. For the most part 16-bit ints work fine with these
libraries, though I haven't thoroughly checked for reliance on 32 bits. If
you'd like well-tested support, contact me. I'm not sure whether supporting
16-bit ints provides much value.


Interface Conventions
----------------------

If a function will keep a pointer to an object passed, to make this clear in
source code it will take a pointer rather than a reference.

Multi-word names have an underscore '_' separator between individual words.

Functions are named with lowercase words. Functions which perform an action
with side-effects are named with a verb phrase (i.e. load, move, run).
Functions which set or return the value of a piece of state are named using a
noun phrase (i.e. loaded, moved, running).

Classes are named with capitalized words. Only the first letter of an acronym
is capitalized. Class names are nouns, sometimes suggestive of what they do
(i.e. File_Scanner).

Structure, enumeration, and typedefs to these and built-in types are named
using lowercase words with a _t suffix.

Macros are named with all-uppercase words.

Internal names which can't be hidden due to technical reasons have an
underscore '_' suffix.


-- 
Shay Green <hotpop.com@blargg> (swap to e-mail)
