Mercurial > audlegacy
view Plugins/Input/console/notes.txt @ 250:b9e6cdce7219 trunk
[svn] Reduce code duplication and add a return statement.
author | chainsaw |
---|---|
date | Sat, 03 Dec 2005 09:27:11 -0800 |
parents | 252843aac42f |
children | 7c5e886205ef |
line wrap: on
line source
Game_Music_Emu Notes Architecture ------------ This library has several emulator classes derived from common interface classes. Music_Emu specifies the main interface, and Classic_Emu adds features available only for "classic" systems (frequency equalization and customizable multi-channel sound buffer). To play a given game music file, do the following: - Determine its file type - Create and set up an appropriate emulator - Load file header and file data into emulator - Start desired track - When samples are needed, call play() - When done, delete emulator Each emulator type defines a nested header_t structure type with members for the file header. When loading a file, the emulators expect the file header to have already been loaded; this allows the caller to use header fields like the game name and music author. See Music_Emu.h and Classic_Emu.h for reference. Error handling -------------- Functions which can fail have a return type of blargg_err_t, which is a pointer to an error string (const char*). If the function is successful it returns blargg_success (NULL), otherwise it returns a pointer to an error string. To allow compatibility with older C++ compilers, no exceptions are thrown by any of the modules. The library is exception-safe, and any exceptions which occur are not intercepted. Due to the different ways compiler runtime libraries handle out-of-memory errors, if the library encounters one it will be reported in one of two ways: if the compiler is configured to throw an exception when operator new can't satisfy a request (which is the case in ISO C++), it is allowed to propagate normally, otherwise the error string "Out of memory" is returned. 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. 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 help. 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 order of bytes in multibyte types. These will cause a compilation error if the order can't be determined. If this occurs, define the appropriate symbol. 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 if your compiler supports bool, otherwise 0. If your compiler supports namespaces, blargg_common.h uses standard headers with the "c" prefix to avoid bringing names from std into the global namespace. If your compiler supports namespaces but this isn't being detected by blargg_common.h, #define BLARGG_COMPILER_HAS_NAMESPACE to 1 in your config.h file. If you have any problems with "blargg_common.h", contact me. Game Music File Handling ------------------------ Game music files include text fields with information about the game and track. Each emulator's header_t defines the basic fields (game, song, author, copyright, track_count) supported by that music type, or has an enum { field = 0 } if unsupported. This allows the same code to be used for parsing each header if it checks that the field is non-zero. Text fields in most game music formats won't have a nul terminator if the string completely fills the field. The demos show one way to handle this. This library is focused on playback only and the emulators don't parse extended text fields, since this can be complex for some formats and can be done by the caller. To load the NSFE format, it must be parsed first and an NSF header must be made in memory and passed Nsf_Emu. See the Game Music Box source code for an example of this: http://www.slack.net/~ant/game-music-box/dev.html Frequency equalization ---------------------- The classic emulators allow frequency equalization to be adjusted; Classic_Emu::equalizer_t( treble, cutoff, bass ) specifies low-pass and high-pass filtering. Low-pass is 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 ... High-pass is a steep rolloff which passes -3dB attenuation at 'breakpoint' Hz, where useful frequencies range from 0 to 6000 Hz. For example, with breakpoint = 1000 Hz, the following results: breakpoint = 1000 Hz 0dB ___________ -3dB ,_*---~~~~~ _~ / / | | -21dB - - - - - - - - - - - - - 0 1000 Hz 4000 Hz Each emulator defaults to a profile that approximates its particular console's sound quality; this default can be determined by getting the current equalization just after creating the emulator. See Classic_Emu.h for reference. Emulator gain control --------------------- Each emulator allows its gain to be adjusted. The default gains are selected to give consistent relative volumes between emulators without resulting in excessive clamping of samples that would otherwise go beyond the 16-bit range. A gain of 1.0 results in a conservative volume that rarely requires any clamping to stay within the 16-bit sample range. Clamping samples to 16 bits is handled by the library. Output sample rate ------------------ Each emulator has a way of specifying the output sample rate during initialization. All the emulators use internal band-limiting, so there is no reason to use a sample rate above 48kHz unless the sound hardware demands it; 44-48kHz will yield the best results. You could use the following code to choose a rate that is both near this range and an integral division of the native rate: long adjust_rate( double native ) { for ( double divider = 1; divider <= 4; divider++ ) { long adjusted = native / divider + 0.5; if ( adjusted <= 56000 ) return adjusted; } return 44100; // give up; CD rate probably works well enough } Interface conventions ---------------------- If a function will keep a pointer to an object passed, to make this clear in source code it takes 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. Misc ---- Special thanks to Chris Moeller (kode54) for help with library testing and feedback. His openspc++ library in C++ was an essential starting point and framework for developing the SPC emulator. Brad Martin's excellent SNES DSP emulator (also part of openspc++) provided an essential foundation for the DSP core.