mirror of
https://github.com/DrBeef/Raze.git
synced 2024-12-15 23:21:21 +00:00
718112a8fe
Currently none of these is being used, but eventually they will, once more code gets ported over. So it's better to have them right away and avoid editing the project file too much, only to revert that later.
376 lines
15 KiB
Text
376 lines
15 KiB
Text
Game_Music_Emu 0.6.2
|
|
--------------------
|
|
Author : Shay Green <gblargg@gmail.com>
|
|
Maintainer : Michael Pyne <mpyne@purinchu.net>
|
|
Website : https://bitbucket.org/mpyne/game-music-emu/
|
|
Source : https://bitbucket.org/mpyne/game-music-emu/
|
|
License : GNU Lesser General Public License (LGPL), see LICENSE.txt
|
|
|
|
Contents
|
|
--------
|
|
* Overview
|
|
* Error handling
|
|
* Emulator types
|
|
* M3U playlist support
|
|
* Information fields
|
|
* Track length
|
|
* Loading file data
|
|
* Sound parameters
|
|
* VGM/GYM YM2413 & YM2612 FM sound
|
|
* Modular construction
|
|
* Obscure features
|
|
* Solving problems
|
|
* Thanks
|
|
|
|
|
|
Overview
|
|
--------
|
|
This library can open game music files, play tracks, and read game and
|
|
track information tags. To play a game music file, do the following:
|
|
|
|
* Open the file with gme_open_file()
|
|
* Start a track with gme_start_track();
|
|
* Generate samples as needed with gme_play()
|
|
* Play samples through speaker using your operating system
|
|
* Delete emulator when done with gme_delete()
|
|
|
|
Your code must arrange for the generated samples to be played through
|
|
the computer's speaker using whatever method your operating system
|
|
requires.
|
|
|
|
There are many additional features available; you can:
|
|
|
|
* Determine of the type of a music file without opening it with
|
|
gme_identify_*()
|
|
* Load just the file's information tags with gme_info_only
|
|
* Load from a block of memory rather than a file with gme_load_data()
|
|
* Arrange for a fade-out at a particular time with gme_set_fade
|
|
* Find when a track has ended with gme_track_ended()
|
|
* Seek to a new time in the track with gme_seek()
|
|
* Load an extended m3u playlist with gme_load_m3u()
|
|
* Get a list of the voices (channels) and mute them individually with
|
|
gme_voice_names() and gme_mute_voice()
|
|
* Change the playback tempo without affecting pitch with gme_set_tempo()
|
|
* Adjust treble/bass equalization with gme_set_equalizer()
|
|
* Associate your own data with an emulator and later get it back with
|
|
gme_set_user_data()
|
|
* Register a function of yours to be called back when the emulator is
|
|
deleted with gme_set_user_cleanup()
|
|
|
|
Refer to gme.h for a comprehensive summary of features.
|
|
|
|
|
|
Error handling
|
|
--------------
|
|
Functions which can fail have a return type of gme_err_t, which is a
|
|
pointer to an error string (const char*). If a function is successful it
|
|
returns NULL. Errors that you can easily avoid are checked with debug
|
|
assertions; gme_err_t return values are only used for genuine run-time
|
|
errors that can't be easily predicted in advance (out of memory, I/O
|
|
errors, incompatible file data). Your code should check all error
|
|
values.
|
|
|
|
When loading a music file in the wrong emulator or trying to load a
|
|
non-music file, gme_wrong_file_type is returned. You can check for this
|
|
error in C++ like this:
|
|
|
|
gme_err_t err = gme_open_file( path, &emu );
|
|
if ( err == gme_wrong_file_type )
|
|
...
|
|
|
|
To check for minor problems, call gme_warning() to get a string
|
|
describing the last warning. Your player should allow the user some way
|
|
of knowing when this is the case, since these minor errors could affect
|
|
playback. Without this information the user can't solve problems as
|
|
well. When playing a track, gme_warning() returns minor playback-related
|
|
problems (major playback problems end the track immediately and set the
|
|
warning string).
|
|
|
|
|
|
Emulator types
|
|
--------------
|
|
The library includes several game music emulators that each support a
|
|
different file type. Each is identified by a gme_type_t constant defined
|
|
in gme.h, for example gme_nsf_emu is for the NSF emulator. If you use
|
|
gme_open_file() or gme_open_data(), the library does the work of
|
|
determining the file type and creating an appropriate emulator. If you
|
|
want more control over this process, read on.
|
|
|
|
There are two basic ways to identify a game music file's type: look at
|
|
its file extension, or read the header data. The library includes
|
|
functions to help with both methods. The first is preferable because it
|
|
is fast and the most common way to identify files. Sometimes the
|
|
extension is lost or wrong, so the header must be read.
|
|
|
|
Use gme_identify_extension() to find the correct game music type based
|
|
on a filename. To identify a file based on its extension and header
|
|
contents, use gme_identify_file(). If you read the header data yourself,
|
|
use gme_identify_header().
|
|
|
|
If you want to remove support for some music types to reduce your
|
|
executable size, edit GME_TYPE_LIST in blargg_config.h. For example, to
|
|
support just NSF and GBS, use this:
|
|
|
|
#define GME_TYPE_LIST \
|
|
gme_nsf_type,\
|
|
gme_gbs_type
|
|
|
|
|
|
M3U playlist support
|
|
--------------------
|
|
The library supports playlists in an extended m3u format with
|
|
gme_load_m3u() to give track names and times to multi-song formats: AY,
|
|
GBS, HES, KSS, NSF, NSFE, and SAP. Some aspects of the file format
|
|
itself is not well-defined so some m3u files won't work properly
|
|
(particularly those provided with KSS files). Only m3u files referencing
|
|
a single file are supported; your code must handle m3u files covering
|
|
more than one game music file, though it can use the built-in m3u
|
|
parsing provided by the library.
|
|
|
|
|
|
Information fields
|
|
------------------
|
|
Support is provided for the various text fields and length information
|
|
in a file with gme_track_info(). If you just need track information for
|
|
a file (for example, building a playlist), use gme_new_info() in place
|
|
of gme_new_emu(), load the file normally, then you can access the track
|
|
count and info, but nothing else.
|
|
|
|
M3U VGM GYM SPC SAP NSFE NSF AY GBS HES KSS
|
|
-------------------------------------------------------
|
|
Track Count | * * * * * * * * *
|
|
|
|
|
System | * * * * * * * * * *
|
|
|
|
|
Game | * * * * * * *
|
|
|
|
|
Song | * * * * * * *
|
|
|
|
|
Author | * * * * * * * *
|
|
|
|
|
Copyright | * * * * * * * *
|
|
|
|
|
Comment | * * * *
|
|
|
|
|
Dumper | * * * *
|
|
|
|
|
Length | * * * * * *
|
|
|
|
|
Intro Length| * * *
|
|
|
|
|
Loop Length | * * *
|
|
|
|
As listed above, the HES and KSS file formats don't include a track
|
|
count, and tracks are often scattered over the 0-255 range, so an m3u
|
|
playlist for these is a must.
|
|
|
|
Unavailable text fields are set to an empty string and times to -1. Your
|
|
code should be prepared for any combination of available and unavailable
|
|
fields, as a particular music file might not use all of the supported
|
|
fields listed above.
|
|
|
|
Currently text fields are truncated to 255 characters. Obscure fields of
|
|
some formats are not currently decoded; contact me if you want one
|
|
added.
|
|
|
|
|
|
Track length
|
|
------------
|
|
The library leaves it up to you as to when to stop playing a track. You
|
|
can ask for available length information and then tell the library what
|
|
time it should start fading the track with gme_set_fade(). By default it
|
|
also continually checks for 6 or more seconds of silence to mark the end
|
|
of a track. Here is a reasonable algorithm you can use to decide how
|
|
long to play a track:
|
|
|
|
* If the track length is > 0, use it
|
|
* If the loop length > 0, play for intro + loop * 2
|
|
* Otherwise, default to 2.5 minutes (150000 msec)
|
|
|
|
If you want to play a track longer than normal, be sure the loop length
|
|
isn't zero. See Music_Player.cpp around line 145 for example code.
|
|
|
|
By default, the library skips silence at the beginning of a track. It
|
|
also continually checks for the end of a non-looping track by watching
|
|
for 6 seconds of unbroken silence. When doing this is scans *ahead* by
|
|
several seconds so it can report the end of the track after only one
|
|
second of silence has actually played. This feature can be disabled with
|
|
gme_ignore_silence().
|
|
|
|
|
|
Loading file data
|
|
-----------------
|
|
The library allows file data to be loaded in many different ways. All
|
|
load functions return an error which you should check. The following
|
|
examples assume these variables:
|
|
|
|
Music_Emu* emu;
|
|
gme_err_t error;
|
|
|
|
If you're letting the library determine a file's type, you can use
|
|
either gme_open_file() or gme_open_data():
|
|
|
|
error = gme_open_file( pathname, &emu );
|
|
error = gme_open_data( pointer, size, &emu );
|
|
|
|
If you're manually determining file type and using used gme_new_emu() to
|
|
create an emulator, you can use the following methods of loading:
|
|
|
|
* From a block of memory:
|
|
|
|
error = gme_load_data( emu, pointer, size );
|
|
|
|
* Have library call your function to read data:
|
|
|
|
gme_err_t my_read( void* my_data, void* out, long count )
|
|
{
|
|
// code that reads 'count' bytes into 'out' buffer
|
|
// and return 0 if no error
|
|
}
|
|
|
|
error = gme_load_custom( emu, my_read, file_size, my_data );
|
|
|
|
|
|
Sound parameters
|
|
----------------
|
|
All emulators support an arbitrary output sampling rate. A rate of 44100
|
|
Hz should work well on most systems. Since band-limited synthesis is
|
|
used, a sampling rate above 48000 Hz is not necessary and will actually
|
|
reduce sound quality and performance.
|
|
|
|
All emulators also support adjustable gain, mainly for the purpose of
|
|
getting consistent volume between different music formats and avoiding
|
|
excessive modulation. The gain can only be set *before* setting the
|
|
emulator's sampling rate, so it's not useful as a general volume
|
|
control. The default gains of emulators are set so that they give
|
|
generally similar volumes, though some soundtracks are significantly
|
|
louder or quieter than normal.
|
|
|
|
Some emulators support adjustable treble and bass frequency equalization
|
|
(AY, GBS, HES, KSS, NSF, NSFE, SAP, VGM) using set_equalizer().
|
|
Parameters are specified using gme_equalizer_t eq = { treble_dB,
|
|
bass_freq }. Treble_dB sets the treble level (in dB), where 0.0 dB gives
|
|
normal treble; -200.0 dB is quite muffled, and 5.0 dB emphasizes treble
|
|
for an extra crisp sound. Bass_freq sets the frequency where bass
|
|
response starts to diminish; 15 Hz is normal, 0 Hz gives maximum bass,
|
|
and 15000 Hz removes all bass. For example, the following makes the
|
|
sound extra-crisp but lacking bass:
|
|
|
|
gme_equalizer_t eq = { 5.0, 1000 };
|
|
gme_set_equalizer( music_emu, &eq );
|
|
|
|
Each emulator's equalization defaults to approximate the particular
|
|
console's sound quality; this default can be determined by calling
|
|
equalizer() just after creating the emulator. The Music_Emu::tv_eq
|
|
profile gives sound as if coming from a TV speaker, and some emulators
|
|
include other profiles for different versions of the system. For
|
|
example, to use Famicom sound equalization with the NSF emulator, do the
|
|
following:
|
|
|
|
music_emu->set_equalizer( Nsf_Emu::famicom_eq );
|
|
|
|
|
|
VGM/GYM YM2413 & YM2612 FM sound
|
|
--------------------------------
|
|
The library plays Sega Genesis/Mega Drive music using a YM2612 FM sound
|
|
chip emulator based on the Gens project. Because this has some
|
|
inaccuracies, other YM2612 emulators can be used in its place by
|
|
re-implementing the interface in YM2612_Emu.h. Available on my website
|
|
is a modified version of MAME's YM2612 emulator, which sounds better in
|
|
some ways and whose author is still making improvements.
|
|
|
|
VGM music files using the YM2413 FM sound chip are also supported, but a
|
|
YM2413 emulator isn't included with the library due to technical
|
|
reasons. I have put one of the available YM2413 emulators on my website
|
|
that can be used directly.
|
|
|
|
|
|
Modular construction
|
|
--------------------
|
|
The library is made of many fairly independent modules. If you're using
|
|
only one music file emulator, you can eliminate many of the library
|
|
sources from your program. Refer to the files list in readme.txt to get
|
|
a general idea of what can be removed, and be sure to edit GME_TYPE_LIST
|
|
(see "Emulator types" above). Post to the forum if you'd like me to put
|
|
together a smaller version for a particular use, as this only takes me a
|
|
few minutes to do.
|
|
|
|
If you want to use one of the individual sound chip emulators (or CPU
|
|
cores) in your own console emulator, first check the libraries page on
|
|
my website since I have released several of them as stand alone
|
|
libraries with included documentation and examples on their use. If you
|
|
don't find it as a standalone library, contact me and I'll consider
|
|
separating it.
|
|
|
|
The "classic" sound chips use my Blip_Buffer library, which greatly
|
|
simplifies their implementation and efficiently handles band-limited
|
|
synthesis. It is also available as a stand alone library with
|
|
documentation and many examples.
|
|
|
|
|
|
Obscure features
|
|
----------------
|
|
The library's flexibility allows many possibilities. Contact me if you
|
|
want help implementing ideas or removing limitations.
|
|
|
|
* Uses no global/static variables, allowing multiple instances of any
|
|
emulator. This is useful in a music player if you want to allow
|
|
simultaneous recording or scanning of other tracks while one is already
|
|
playing. This will also be useful if your platform disallows global
|
|
data.
|
|
|
|
* Emulators that support a custom sound buffer can have *every* voice
|
|
routed to a different Blip_Buffer, allowing custom processing on each
|
|
voice. For example you could record a Game Boy track as a 4-channel
|
|
sound file.
|
|
|
|
* Defining BLIP_BUFFER_FAST uses lower quality, less-multiply-intensive
|
|
synthesis on "classic" emulators, which might help on some really old
|
|
processors. This significantly lowers sound quality and prevents treble
|
|
equalization. Try this if your platform's processor isn't fast enough
|
|
for normal quality. Even on my ten-year-old 400 MHz Mac, this reduces
|
|
processor usage at most by about 0.6% (from 4% to 3.4%), hardly worth
|
|
the quality loss.
|
|
|
|
|
|
Solving problems
|
|
----------------
|
|
If you're having problems, try the following:
|
|
|
|
* If you're getting garbled sound, try this simple siren generator in
|
|
place of your call to play(). This will quickly tell whether the problem
|
|
is in the library or in your code.
|
|
|
|
static void play_siren( long count, short* out )
|
|
{
|
|
static double a, a2;
|
|
while ( count-- )
|
|
*out++ = 0x2000 * sin( a += .1 + .05*sin( a2+=.00005 ) );
|
|
}
|
|
|
|
* Enable debugging support in your environment. This enables assertions
|
|
and other run-time checks.
|
|
|
|
* Turn the compiler's optimizer is off. Sometimes an optimizer generates
|
|
bad code.
|
|
|
|
* If multiple threads are being used, ensure that only one at a time is
|
|
accessing a given set of objects from the library. This library is not
|
|
in general thread-safe, though independent objects can be used in
|
|
separate threads.
|
|
|
|
* If all else fails, see if the demos work.
|
|
|
|
|
|
Thanks
|
|
------
|
|
Big thanks to Chris Moeller (kode54) for help with library testing and
|
|
feedback, for maintaining the Foobar2000 plugin foo_gep based on it, and
|
|
for original work on openspc++ that was used when developing Spc_Emu.
|
|
Brad Martin's excellent OpenSPC SNES DSP emulator worked well from the
|
|
start. Also thanks to Richard Bannister, Mahendra Tallur, Shazz,
|
|
nenolod, theHobbit, Johan Samuelsson, and nes6502 for testing, using,
|
|
and giving feedback for the library in their respective game music
|
|
players. More recently, Lucas Paul and Michael Pyne have helped nudge the
|
|
library into a public repository and get its interface more stable for use
|
|
in shared libraries.
|