Updated Game_Music_Emu to support Game Boy DMG sound in VGM files

CQTexperiment
Chris Moeller 2014-11-02 18:28:28 -08:00
parent 0290c1a3dd
commit 4acbb21f99
8 changed files with 3384 additions and 3300 deletions

View File

@ -161,6 +161,12 @@ void Gb_Apu::set_tempo( double t )
frame_period = t ? blip_time_t (frame_period / t) : blip_time_t(0); frame_period = t ? blip_time_t (frame_period / t) : blip_time_t(0);
} }
void Gb_Apu::set_hacks( unsigned int mask )
{
wave.set_volume_hack((mask & 1) != 0);
noise.set_volume_hack((mask & 2) == 0);
}
Gb_Apu::Gb_Apu() Gb_Apu::Gb_Apu()
{ {
wave.wave_ram = &regs [wave_ram - io_addr]; wave.wave_ram = &regs [wave_ram - io_addr];
@ -187,6 +193,7 @@ Gb_Apu::Gb_Apu()
set_tempo( 1.0 ); set_tempo( 1.0 );
volume_ = 1.0; volume_ = 1.0;
reset(); reset();
set_hacks(4);
} }
void Gb_Apu::run_until_( blip_time_t end_time ) void Gb_Apu::run_until_( blip_time_t end_time )

View File

@ -84,6 +84,11 @@ public:
// Loads state. You should call reset() BEFORE this. // Loads state. You should call reset() BEFORE this.
blargg_err_t load_state( gb_apu_state_t const& in ); blargg_err_t load_state( gb_apu_state_t const& in );
// Enable hacks (bitmask):
// 0x01 = Double wave channel volume
// 0x02 = Low noise channel volume (disable doubling it)
void set_hacks( unsigned int mask );
private: private:
// noncopyable // noncopyable
Gb_Apu( const Gb_Apu& ); Gb_Apu( const Gb_Apu& );

View File

@ -571,6 +571,7 @@ void Gb_Noise::run( blip_time_t time, blip_time_t end_time )
Blip_Synth_Fast const* const synth = fast_synth; // cache Blip_Synth_Fast const* const synth = fast_synth; // cache
// Output amplitude transitions // Output amplitude transitions
if (volume_hack) vol <<= 1;
int delta = -vol; int delta = -vol;
do do
{ {
@ -603,11 +604,11 @@ void Gb_Wave::run( blip_time_t time, blip_time_t end_time )
#if GB_APU_NO_AGB #if GB_APU_NO_AGB
static byte const shifts [4] = { 4+4, 0+4, 1+4, 2+4 }; static byte const shifts [4] = { 4+4, 0+4, 1+4, 2+4 };
int const volume_idx = regs [2] >> 5 & 3; int const volume_idx = regs [2] >> 5 & 3;
int const volume_shift = shifts [volume_idx]; int const volume_shift = shifts [volume_idx] - (volume_hack ? 1 : 0);
int const volume_mul = 1; int const volume_mul = 1;
#else #else
static byte const volumes [8] = { 0, 4, 2, 1, 3, 3, 3, 3 }; static byte const volumes [8] = { 0, 4, 2, 1, 3, 3, 3, 3 };
int const volume_shift = 2 + 4; int const volume_shift = 2 + 4 - (volume_hack ? 1 : 0);
int const volume_idx = regs [2] >> 5 & (agb_mask | 3); // 2 bits on DMG/CGB, 3 on AGB int const volume_idx = regs [2] >> 5 & (agb_mask | 3); // 2 bits on DMG/CGB, 3 on AGB
int const volume_mul = volumes [volume_idx]; int const volume_mul = volumes [volume_idx];
#endif #endif

View File

@ -114,6 +114,8 @@ class Gb_Noise : public Gb_Env {
public: public:
int divider; // noise has more complex frequency divider setup int divider; // noise has more complex frequency divider setup
bool volume_hack;
void run( blip_time_t, blip_time_t ); void run( blip_time_t, blip_time_t );
void write_register( int frame_phase, int reg, int old_data, int data ); void write_register( int frame_phase, int reg, int old_data, int data );
@ -123,7 +125,11 @@ public:
divider = 0; divider = 0;
Gb_Env::reset(); Gb_Env::reset();
delay = 4 * clk_mul; // TODO: remove? delay = 4 * clk_mul; // TODO: remove?
volume_hack = true;
} }
void set_volume_hack( bool enable );
private: private:
enum { period2_mask = 0x1FFFF }; enum { period2_mask = 0x1FFFF };
@ -132,9 +138,13 @@ private:
unsigned lfsr_mask() const { return (regs [3] & 0x08) ? ~0x4040 : ~0x4000; } unsigned lfsr_mask() const { return (regs [3] & 0x08) ? ~0x4040 : ~0x4000; }
}; };
inline void Gb_Noise::set_volume_hack( bool enable ) { volume_hack = enable; }
class Gb_Wave : public Gb_Osc { class Gb_Wave : public Gb_Osc {
public: public:
int sample_buf; // last wave RAM byte read (hardware has this as well) int sample_buf; // last wave RAM byte read (hardware has this as well)
bool volume_hack;
void write_register( int frame_phase, int reg, int old_data, int data ); void write_register( int frame_phase, int reg, int old_data, int data );
void run( blip_time_t, blip_time_t ); void run( blip_time_t, blip_time_t );
@ -147,6 +157,7 @@ public:
{ {
sample_buf = 0; sample_buf = 0;
Gb_Osc::reset(); Gb_Osc::reset();
volume_hack = false;
} }
private: private:
@ -165,6 +176,8 @@ private:
int dac_enabled() const { return regs [0] & 0x80; } int dac_enabled() const { return regs [0] & 0x80; }
void corrupt_wave(); void corrupt_wave();
void set_volume_hack( bool enable );
BOOST::uint8_t* wave_bank() const { return &wave_ram [(~regs [0] & bank40_mask) >> 2 & agb_mask]; } BOOST::uint8_t* wave_bank() const { return &wave_ram [(~regs [0] & bank40_mask) >> 2 & agb_mask]; }
@ -172,6 +185,8 @@ private:
int access( int addr ) const; int access( int addr ) const;
}; };
inline void Gb_Wave::set_volume_hack( bool enable ) { volume_hack = enable; }
inline int Gb_Wave::read( int addr ) const inline int Gb_Wave::read( int addr ) const
{ {
int index = access( addr ); int index = access( addr );

View File

@ -1,17 +1,17 @@
// Game_Music_Emu $vers. http://www.slack.net/~ant/ // Game_Music_Emu $vers. http://www.slack.net/~ant/
#include "Gbs_Emu.h" #include "Gbs_Emu.h"
/* Copyright (C) 2003-2009 Shay Green. This module is free software; you /* Copyright (C) 2003-2009 Shay Green. This module is free software; you
can redistribute it and/or modify it under the terms of the GNU Lesser can redistribute it and/or modify it under the terms of the GNU Lesser
General Public License as published by the Free Software Foundation; either General Public License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version. This version 2.1 of the License, or (at your option) any later version. This
module is distributed in the hope that it will be useful, but WITHOUT ANY module is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details. You should have received a copy of the GNU Lesser General Public details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation, License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
#include "blargg_source.h" #include "blargg_source.h"
@ -21,11 +21,11 @@ Gbs_Emu::equalizer_t const Gbs_Emu::headphones_eq = { 0.0, 30, 0,0,0,0,0,0,0
Gbs_Emu::Gbs_Emu() Gbs_Emu::Gbs_Emu()
{ {
sound_hardware = sound_gbs; sound_hardware = sound_gbs;
enable_clicking( false ); enable_clicking( false );
set_type( gme_gbs_type ); set_type( gme_gbs_type );
set_silence_lookahead( 6 ); set_silence_lookahead( 6 );
set_max_initial_silence( 21 ); set_max_initial_silence( 21 );
set_gain( 1.2 ); set_gain( 1.2 );
// kind of midway between headphones and speaker // kind of midway between headphones and speaker
@ -33,135 +33,135 @@ Gbs_Emu::Gbs_Emu()
set_equalizer( eq ); set_equalizer( eq );
} }
Gbs_Emu::~Gbs_Emu() { } Gbs_Emu::~Gbs_Emu() { }
void Gbs_Emu::unload() void Gbs_Emu::unload()
{ {
core_.unload(); core_.unload();
Music_Emu::unload(); Music_Emu::unload();
} }
// Track info // Track info
static void copy_gbs_fields( Gbs_Emu::header_t const& h, track_info_t* out ) static void copy_gbs_fields( Gbs_Emu::header_t const& h, track_info_t* out )
{ {
GME_COPY_FIELD( h, out, game ); GME_COPY_FIELD( h, out, game );
GME_COPY_FIELD( h, out, author ); GME_COPY_FIELD( h, out, author );
GME_COPY_FIELD( h, out, copyright ); GME_COPY_FIELD( h, out, copyright );
} }
static void hash_gbs_file( Gbs_Emu::header_t const& h, byte const* data, int data_size, Music_Emu::Hash_Function& out ) static void hash_gbs_file( Gbs_Emu::header_t const& h, byte const* data, int data_size, Music_Emu::Hash_Function& out )
{ {
out.hash_( &h.vers, sizeof(h.vers) ); out.hash_( &h.vers, sizeof(h.vers) );
out.hash_( &h.track_count, sizeof(h.track_count) ); out.hash_( &h.track_count, sizeof(h.track_count) );
out.hash_( &h.first_track, sizeof(h.first_track) ); out.hash_( &h.first_track, sizeof(h.first_track) );
out.hash_( &h.load_addr[0], sizeof(h.load_addr) ); out.hash_( &h.load_addr[0], sizeof(h.load_addr) );
out.hash_( &h.init_addr[0], sizeof(h.init_addr) ); out.hash_( &h.init_addr[0], sizeof(h.init_addr) );
out.hash_( &h.play_addr[0], sizeof(h.play_addr) ); out.hash_( &h.play_addr[0], sizeof(h.play_addr) );
out.hash_( &h.stack_ptr[0], sizeof(h.stack_ptr) ); out.hash_( &h.stack_ptr[0], sizeof(h.stack_ptr) );
out.hash_( &h.timer_modulo, sizeof(h.timer_modulo) ); out.hash_( &h.timer_modulo, sizeof(h.timer_modulo) );
out.hash_( &h.timer_mode, sizeof(h.timer_mode) ); out.hash_( &h.timer_mode, sizeof(h.timer_mode) );
out.hash_( data, data_size ); out.hash_( data, data_size );
} }
blargg_err_t Gbs_Emu::track_info_( track_info_t* out, int ) const blargg_err_t Gbs_Emu::track_info_( track_info_t* out, int ) const
{ {
copy_gbs_fields( header(), out ); copy_gbs_fields( header(), out );
return blargg_ok; return blargg_ok;
} }
struct Gbs_File : Gme_Info_ struct Gbs_File : Gme_Info_
{ {
Gbs_Emu::header_t const* h; Gbs_Emu::header_t const* h;
Gbs_File() { set_type( gme_gbs_type ); } Gbs_File() { set_type( gme_gbs_type ); }
blargg_err_t load_mem_( byte const begin [], int size ) blargg_err_t load_mem_( byte const begin [], int size )
{ {
h = ( Gbs_Emu::header_t * ) begin; h = ( Gbs_Emu::header_t * ) begin;
set_track_count( h->track_count ); set_track_count( h->track_count );
if ( !h->valid_tag() ) if ( !h->valid_tag() )
return blargg_err_file_type; return blargg_err_file_type;
return blargg_ok; return blargg_ok;
} }
blargg_err_t track_info_( track_info_t* out, int ) const blargg_err_t track_info_( track_info_t* out, int ) const
{ {
copy_gbs_fields( Gbs_Emu::header_t( *h ), out ); copy_gbs_fields( Gbs_Emu::header_t( *h ), out );
return blargg_ok; return blargg_ok;
} }
blargg_err_t hash_( Hash_Function& out ) const blargg_err_t hash_( Hash_Function& out ) const
{ {
hash_gbs_file( *h, file_begin() + h->size, file_end() - file_begin() - h->size, out ); hash_gbs_file( *h, file_begin() + h->size, file_end() - file_begin() - h->size, out );
return blargg_ok; return blargg_ok;
} }
}; };
static Music_Emu* new_gbs_emu () { return BLARGG_NEW Gbs_Emu ; } static Music_Emu* new_gbs_emu () { return BLARGG_NEW Gbs_Emu ; }
static Music_Emu* new_gbs_file() { return BLARGG_NEW Gbs_File; } static Music_Emu* new_gbs_file() { return BLARGG_NEW Gbs_File; }
gme_type_t_ const gme_gbs_type [1] = {{ "Game Boy", 0, &new_gbs_emu, &new_gbs_file, "GBS", 1 }}; gme_type_t_ const gme_gbs_type [1] = {{ "Game Boy", 0, &new_gbs_emu, &new_gbs_file, "GBS", 1 }};
// Setup // Setup
blargg_err_t Gbs_Emu::load_( Data_Reader& in ) blargg_err_t Gbs_Emu::load_( Data_Reader& in )
{ {
RETURN_ERR( core_.load( in ) ); RETURN_ERR( core_.load( in ) );
set_warning( core_.warning() ); set_warning( core_.warning() );
set_track_count( header().track_count ); set_track_count( header().track_count );
set_voice_count( Gb_Apu::osc_count ); set_voice_count( Gb_Apu::osc_count );
core_.apu().volume( gain() ); core_.apu().volume( gain() );
static const char* const names [Gb_Apu::osc_count] = { static const char* const names [Gb_Apu::osc_count] = {
"Square 1", "Square 2", "Wave", "Noise" "Square 1", "Square 2", "Wave", "Noise"
}; };
set_voice_names( names ); set_voice_names( names );
static int const types [Gb_Apu::osc_count] = { static int const types [Gb_Apu::osc_count] = {
wave_type+1, wave_type+2, wave_type+3, mixed_type+1 wave_type+1, wave_type+2, wave_type+3, mixed_type+1
}; };
set_voice_types( types ); set_voice_types( types );
return setup_buffer( 4194304 ); return setup_buffer( 4194304 );
} }
void Gbs_Emu::update_eq( blip_eq_t const& eq ) void Gbs_Emu::update_eq( blip_eq_t const& eq )
{ {
core_.apu().treble_eq( eq ); core_.apu().treble_eq( eq );
} }
void Gbs_Emu::set_voice( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r ) void Gbs_Emu::set_voice( int i, Blip_Buffer* c, Blip_Buffer* l, Blip_Buffer* r )
{ {
core_.apu().set_output( i, c, l, r ); core_.apu().set_output( i, c, l, r );
} }
void Gbs_Emu::set_tempo_( double t ) void Gbs_Emu::set_tempo_( double t )
{ {
core_.set_tempo( t ); core_.set_tempo( t );
} }
blargg_err_t Gbs_Emu::start_track_( int track ) blargg_err_t Gbs_Emu::start_track_( int track )
{ {
sound_t mode = sound_hardware; sound_t mode = sound_hardware;
if ( mode == sound_gbs ) if ( mode == sound_gbs )
mode = (header().timer_mode & 0x80) ? sound_cgb : sound_dmg; mode = (header().timer_mode & 0x80) ? sound_cgb : sound_dmg;
RETURN_ERR( core_.start_track( track, (Gb_Apu::mode_t) mode ) ); RETURN_ERR( core_.start_track( track, (Gb_Apu::mode_t) mode ) );
// clear buffer AFTER track is started, eliminating initial click // clear buffer AFTER track is started, eliminating initial click
return Classic_Emu::start_track_( track ); return Classic_Emu::start_track_( track );
} }
blargg_err_t Gbs_Emu::run_clocks( blip_time_t& duration, int ) blargg_err_t Gbs_Emu::run_clocks( blip_time_t& duration, int )
{ {
return core_.end_frame( duration ); return core_.end_frame( duration );
} }
blargg_err_t Gbs_Emu::hash_( Hash_Function& out ) const blargg_err_t Gbs_Emu::hash_( Hash_Function& out ) const
{ {
hash_gbs_file( header(), core_.rom_().begin(), core_.rom_().file_size(), out ); hash_gbs_file( header(), core_.rom_().begin(), core_.rom_().file_size(), out );
return blargg_ok; return blargg_ok;
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,346 +1,353 @@
// Sega VGM music file emulator core // Sega VGM music file emulator core
// Game_Music_Emu $vers // Game_Music_Emu $vers
#ifndef VGM_CORE_H #ifndef VGM_CORE_H
#define VGM_CORE_H #define VGM_CORE_H
#include "Gme_Loader.h" #include "Gme_Loader.h"
#include "Ymz280b_Emu.h" #include "Ymz280b_Emu.h"
#include "Ymf262_Emu.h" #include "Ymf262_Emu.h"
#include "Ym2612_Emu.h" #include "Ym2612_Emu.h"
#include "Ym2610b_Emu.h" #include "Ym2610b_Emu.h"
#include "Ym2608_Emu.h" #include "Ym2608_Emu.h"
#include "Ym3812_Emu.h" #include "Ym3812_Emu.h"
#include "Ym2413_Emu.h" #include "Ym2413_Emu.h"
#include "Ym2151_Emu.h" #include "Ym2151_Emu.h"
#include "C140_Emu.h" #include "C140_Emu.h"
#include "SegaPcm_Emu.h" #include "SegaPcm_Emu.h"
#include "Rf5C68_Emu.h" #include "Rf5C68_Emu.h"
#include "Rf5C164_Emu.h" #include "Rf5C164_Emu.h"
#include "Pwm_Emu.h" #include "Pwm_Emu.h"
#include "Okim6258_Emu.h" #include "Okim6258_Emu.h"
#include "Okim6295_Emu.h" #include "Okim6295_Emu.h"
#include "K051649_Emu.h" #include "K051649_Emu.h"
#include "K053260_Emu.h" #include "K053260_Emu.h"
#include "K054539_Emu.h" #include "K054539_Emu.h"
#include "Qsound_Apu.h" #include "Qsound_Apu.h"
#include "Ym2203_Emu.h" #include "Ym2203_Emu.h"
#include "Ay_Apu.h" #include "Ay_Apu.h"
#include "Hes_Apu.h" #include "Gb_Apu.h"
#include "Sms_Apu.h" #include "Hes_Apu.h"
#include "Multi_Buffer.h" #include "Sms_Apu.h"
#include "Chip_Resampler.h" #include "Multi_Buffer.h"
#include "Chip_Resampler.h"
template<class Emu>
class Chip_Emu : public Emu { template<class Emu>
int last_time; class Chip_Emu : public Emu {
short* out; int last_time;
enum { disabled_time = -1 }; short* out;
public: enum { disabled_time = -1 };
Chip_Emu() { last_time = disabled_time; out = NULL; } public:
void enable( bool b = true ) { last_time = b ? 0 : disabled_time; } Chip_Emu() { last_time = disabled_time; out = NULL; }
bool enabled() const { return last_time != disabled_time; } void enable( bool b = true ) { last_time = b ? 0 : disabled_time; }
void begin_frame( short* buf ) { out = buf; last_time = 0; } bool enabled() const { return last_time != disabled_time; }
void begin_frame( short* buf ) { out = buf; last_time = 0; }
int run_until( int time )
{ int run_until( int time )
int count = time - last_time; {
if ( count > 0 ) int count = time - last_time;
{ if ( count > 0 )
if ( last_time < 0 ) {
return false; if ( last_time < 0 )
last_time = time; return false;
short* p = out; last_time = time;
out += count * Emu::out_chan_count; short* p = out;
Emu::run( count, p ); out += count * Emu::out_chan_count;
} Emu::run( count, p );
return true; }
} return true;
}; }
};
class Vgm_Core : public Gme_Loader {
public: class Vgm_Core : public Gme_Loader {
public:
// VGM file header
struct header_t // VGM file header
{ struct header_t
enum { size_min = 0x40 }; {
enum { size_151 = 0x80 }; enum { size_min = 0x40 };
enum { size_max = 0xC0 }; enum { size_151 = 0x80 };
enum { size_max = 0xC0 };
char tag [4]; // 0x00
byte data_size [4]; // 0x04 char tag [4]; // 0x00
byte version [4]; // 0x08 byte data_size [4]; // 0x04
byte psg_rate [4]; // 0x0C byte version [4]; // 0x08
byte ym2413_rate [4]; // 0x10 byte psg_rate [4]; // 0x0C
byte gd3_offset [4]; // 0x14 byte ym2413_rate [4]; // 0x10
byte track_duration [4]; // 0x18 byte gd3_offset [4]; // 0x14
byte loop_offset [4]; // 0x1C byte track_duration [4]; // 0x18
byte loop_duration [4]; // 0x20 byte loop_offset [4]; // 0x1C
byte frame_rate [4]; // 0x24 v1.01 V byte loop_duration [4]; // 0x20
byte noise_feedback [2]; // 0x28 v1.10 V byte frame_rate [4]; // 0x24 v1.01 V
byte noise_width; // 0x2A byte noise_feedback [2]; // 0x28 v1.10 V
byte sn76489_flags; // 0x2B v1.51 < byte noise_width; // 0x2A
byte ym2612_rate [4]; // 0x2C v1.10 V byte sn76489_flags; // 0x2B v1.51 <
byte ym2151_rate [4]; // 0x30 byte ym2612_rate [4]; // 0x2C v1.10 V
byte data_offset [4]; // 0x34 v1.50 V byte ym2151_rate [4]; // 0x30
byte segapcm_rate [4]; // 0x38 v1.51 V byte data_offset [4]; // 0x34 v1.50 V
byte segapcm_reg [4]; // 0x3C byte segapcm_rate [4]; // 0x38 v1.51 V
byte rf5c68_rate [4]; // 0x40 byte segapcm_reg [4]; // 0x3C
byte ym2203_rate [4]; // 0x44 byte rf5c68_rate [4]; // 0x40
byte ym2608_rate [4]; // 0x48 byte ym2203_rate [4]; // 0x44
byte ym2610_rate [4]; // 0x4C byte ym2608_rate [4]; // 0x48
byte ym3812_rate [4]; // 0x50 byte ym2610_rate [4]; // 0x4C
byte ym3526_rate [4]; // 0x54 byte ym3812_rate [4]; // 0x50
byte y8950_rate [4]; // 0x58 byte ym3526_rate [4]; // 0x54
byte ymf262_rate [4]; // 0x5C byte y8950_rate [4]; // 0x58
byte ymf278b_rate [4]; // 0x60 byte ymf262_rate [4]; // 0x5C
byte ymf271_rate [4]; // 0x64 byte ymf278b_rate [4]; // 0x60
byte ymz280b_rate [4]; // 0x68 byte ymf271_rate [4]; // 0x64
byte rf5c164_rate [4]; // 0x6C byte ymz280b_rate [4]; // 0x68
byte pwm_rate [4]; // 0x70 byte rf5c164_rate [4]; // 0x6C
byte ay8910_rate [4]; // 0x74 byte pwm_rate [4]; // 0x70
byte ay8910_type; // 0x78 byte ay8910_rate [4]; // 0x74
byte ay8910_flags; // 0x79 byte ay8910_type; // 0x78
byte ym2203_ay8910_flags;// 0x7A byte ay8910_flags; // 0x79
byte ym2608_ay8910_flags;// 0x7B byte ym2203_ay8910_flags;// 0x7A
byte volume_modifier; // 0x7C v1.60 V byte ym2608_ay8910_flags;// 0x7B
byte reserved; // 0x7D byte volume_modifier; // 0x7C v1.60 V
byte loop_base; // 0x7E byte reserved; // 0x7D
byte loop_modifier; // 0x7F v1.51 < byte loop_base; // 0x7E
byte gbdmg_rate [4]; // 0x80 v1.61 V byte loop_modifier; // 0x7F v1.51 <
byte nesapu_rate [4]; // 0x84 byte gbdmg_rate [4]; // 0x80 v1.61 V
byte multipcm_rate [4]; // 0x88 byte nesapu_rate [4]; // 0x84
byte upd7759_rate [4]; // 0x8C byte multipcm_rate [4]; // 0x88
byte okim6258_rate [4]; // 0x90 byte upd7759_rate [4]; // 0x8C
byte okim6258_flags; // 0x94 byte okim6258_rate [4]; // 0x90
byte k054539_flags; // 0x95 byte okim6258_flags; // 0x94
byte c140_type; // 0x96 byte k054539_flags; // 0x95
byte reserved_flags; // 0x97 byte c140_type; // 0x96
byte okim6295_rate [4]; // 0x98 byte reserved_flags; // 0x97
byte k051649_rate [4]; // 0x9C byte okim6295_rate [4]; // 0x98
byte k054539_rate [4]; // 0xA0 byte k051649_rate [4]; // 0x9C
byte huc6280_rate [4]; // 0xA4 byte k054539_rate [4]; // 0xA0
byte c140_rate [4]; // 0xA8 byte huc6280_rate [4]; // 0xA4
byte k053260_rate [4]; // 0xAC byte c140_rate [4]; // 0xA8
byte pokey_rate [4]; // 0xB0 byte k053260_rate [4]; // 0xAC
byte qsound_rate [4]; // 0xB4 byte pokey_rate [4]; // 0xB0
byte reserved2 [4]; // 0xB8 byte qsound_rate [4]; // 0xB4
byte extra_offset [4]; // 0xBC byte reserved2 [4]; // 0xB8
byte extra_offset [4]; // 0xBC
// True if header has valid file signature
bool valid_tag() const; // True if header has valid file signature
int size() const; bool valid_tag() const;
void cleanup(); int size() const;
}; void cleanup();
};
// Header for currently loaded file
header_t const& header() const { return _header; } // Header for currently loaded file
header_t const& header() const { return _header; }
// Raw file data, for parsing GD3 tags
byte const* file_begin() const { return Gme_Loader::file_begin(); } // Raw file data, for parsing GD3 tags
byte const* file_end () const { return Gme_Loader::file_end(); } byte const* file_begin() const { return Gme_Loader::file_begin(); }
byte const* file_end () const { return Gme_Loader::file_end(); }
// If file uses FM, initializes FM sound emulator using *sample_rate. If
// *sample_rate is zero, sets *sample_rate to the proper accurate rate and // If file uses FM, initializes FM sound emulator using *sample_rate. If
// uses that. The output of the FM sound emulator is resampled to the // *sample_rate is zero, sets *sample_rate to the proper accurate rate and
// final sampling rate. // uses that. The output of the FM sound emulator is resampled to the
blargg_err_t init_chips( double* fm_rate, bool reinit = false ); // final sampling rate.
blargg_err_t init_chips( double* fm_rate, bool reinit = false );
// True if any FM chips are used by file. Always false until init_fm()
// is called. // True if any FM chips are used by file. Always false until init_fm()
bool uses_fm() const { return ym2612[0].enabled() || ym2413[0].enabled() || ym2151[0].enabled() || c140.enabled() || // is called.
segapcm.enabled() || rf5c68.enabled() || rf5c164.enabled() || pwm.enabled() || okim6258[0].enabled() || okim6295[0].enabled() || bool uses_fm() const { return ym2612[0].enabled() || ym2413[0].enabled() || ym2151[0].enabled() || c140.enabled() ||
k051649.enabled() || k053260.enabled() || k054539.enabled() || ym2203[0].enabled() || ym3812[0].enabled() || ymf262[0].enabled() || segapcm.enabled() || rf5c68.enabled() || rf5c164.enabled() || pwm.enabled() || okim6258[0].enabled() || okim6295[0].enabled() ||
ymz280b.enabled() || ym2610[0].enabled() || ym2608[0].enabled() || qsound[0].enabled() || k051649.enabled() || k053260.enabled() || k054539.enabled() || ym2203[0].enabled() || ym3812[0].enabled() || ymf262[0].enabled() ||
(header().ay8910_rate[0] | header().ay8910_rate[1] | header().ay8910_rate[2] | header().ay8910_rate[3]) || ymz280b.enabled() || ym2610[0].enabled() || ym2608[0].enabled() || qsound[0].enabled() ||
(header().huc6280_rate[0] | header().huc6280_rate[1] | header().huc6280_rate[2] | header().huc6280_rate[3]); } (header().ay8910_rate[0] | header().ay8910_rate[1] | header().ay8910_rate[2] | header().ay8910_rate[3]) ||
(header().huc6280_rate[0] | header().huc6280_rate[1] | header().huc6280_rate[2] | header().huc6280_rate[3]) ||
// Adjusts music tempo, where 1.0 is normal. Can be changed while playing. (header().gbdmg_rate[0] | header().gbdmg_rate[1] | header().gbdmg_rate[2] | header().gbdmg_rate[3]); }
// Loading a file resets tempo to 1.0.
void set_tempo( double ); // Adjusts music tempo, where 1.0 is normal. Can be changed while playing.
// Loading a file resets tempo to 1.0.
void set_sample_rate( int r ) { sample_rate = r; } void set_tempo( double );
// Starts track void set_sample_rate( int r ) { sample_rate = r; }
void start_track();
// Starts track
// Runs PSG-only VGM for msec and returns number of clocks it ran for void start_track();
blip_time_t run_psg( int msec );
// Runs PSG-only VGM for msec and returns number of clocks it ran for
// Plays FM for at most count samples into *out, and returns number of blip_time_t run_psg( int msec );
// samples actually generated (always even). Also runs PSG for blip_time.
int play_frame( blip_time_t blip_time, int count, blip_sample_t out [] ); // Plays FM for at most count samples into *out, and returns number of
// samples actually generated (always even). Also runs PSG for blip_time.
// True if all of file data has been played int play_frame( blip_time_t blip_time, int count, blip_sample_t out [] );
bool track_ended() const { return pos >= file_end(); }
// True if all of file data has been played
// 0 for PSG and YM2612 DAC, 1 for AY, 2 for HuC6280 bool track_ended() const { return pos >= file_end(); }
Stereo_Buffer stereo_buf[3];
// 0 for PSG and YM2612 DAC, 1 for AY, 2 for HuC6280, 3 for GB DMG
// PCM sound is always generated here Stereo_Buffer stereo_buf[4];
Blip_Buffer * blip_buf[2];
// PCM sound is always generated here
// PSG sound chips, for assigning to Blip_Buffer, and setting volume and EQ Blip_Buffer * blip_buf[2];
Sms_Apu psg[2];
Ay_Apu ay[2]; // PSG sound chips, for assigning to Blip_Buffer, and setting volume and EQ
Hes_Apu huc6280[2]; Sms_Apu psg[2];
Ay_Apu ay[2];
// PCM synth, for setting volume and EQ Hes_Apu huc6280[2];
Blip_Synth_Fast pcm; Gb_Apu gbdmg[2];
// FM sound chips // PCM synth, for setting volume and EQ
Chip_Resampler_Emu<Ymf262_Emu> ymf262[2]; Blip_Synth_Fast pcm;
Chip_Resampler_Emu<Ym3812_Emu> ym3812[2];
Chip_Resampler_Emu<Ym2612_Emu> ym2612[2]; // FM sound chips
Chip_Resampler_Emu<Ym2610b_Emu> ym2610[2]; Chip_Resampler_Emu<Ymf262_Emu> ymf262[2];
Chip_Resampler_Emu<Ym2608_Emu> ym2608[2]; Chip_Resampler_Emu<Ym3812_Emu> ym3812[2];
Chip_Resampler_Emu<Ym2413_Emu> ym2413[2]; Chip_Resampler_Emu<Ym2612_Emu> ym2612[2];
Chip_Resampler_Emu<Ym2151_Emu> ym2151[2]; Chip_Resampler_Emu<Ym2610b_Emu> ym2610[2];
Chip_Resampler_Emu<Ym2203_Emu> ym2203[2]; Chip_Resampler_Emu<Ym2608_Emu> ym2608[2];
Chip_Resampler_Emu<Ym2413_Emu> ym2413[2];
// PCM sound chips Chip_Resampler_Emu<Ym2151_Emu> ym2151[2];
Chip_Resampler_Emu<C140_Emu> c140; Chip_Resampler_Emu<Ym2203_Emu> ym2203[2];
Chip_Resampler_Emu<SegaPcm_Emu> segapcm;
Chip_Resampler_Emu<Rf5C68_Emu> rf5c68; // PCM sound chips
Chip_Resampler_Emu<Rf5C164_Emu> rf5c164; Chip_Resampler_Emu<C140_Emu> c140;
Chip_Resampler_Emu<Pwm_Emu> pwm; Chip_Resampler_Emu<SegaPcm_Emu> segapcm;
Chip_Resampler_Emu<Okim6258_Emu> okim6258[2]; int okim6258_hz[2]; Chip_Resampler_Emu<Rf5C68_Emu> rf5c68;
Chip_Resampler_Emu<Okim6295_Emu> okim6295[2]; int okim6295_hz; Chip_Resampler_Emu<Rf5C164_Emu> rf5c164;
Chip_Resampler_Emu<K051649_Emu> k051649; Chip_Resampler_Emu<Pwm_Emu> pwm;
Chip_Resampler_Emu<K053260_Emu> k053260; Chip_Resampler_Emu<Okim6258_Emu> okim6258[2]; int okim6258_hz[2];
Chip_Resampler_Emu<K054539_Emu> k054539; Chip_Resampler_Emu<Okim6295_Emu> okim6295[2]; int okim6295_hz;
Chip_Resampler_Emu<Ymz280b_Emu> ymz280b; int ymz280b_hz; Chip_Resampler_Emu<K051649_Emu> k051649;
Chip_Resampler_Emu<Qsound_Apu> qsound[2]; Chip_Resampler_Emu<K053260_Emu> k053260;
Chip_Resampler_Emu<K054539_Emu> k054539;
// DAC control Chip_Resampler_Emu<Ymz280b_Emu> ymz280b; int ymz280b_hz;
typedef struct daccontrol_data Chip_Resampler_Emu<Qsound_Apu> qsound[2];
{
bool Enable; // DAC control
byte Bank; typedef struct daccontrol_data
} DACCTRL_DATA; {
bool Enable;
byte DacCtrlUsed; byte Bank;
byte DacCtrlUsg[0xFF]; } DACCTRL_DATA;
DACCTRL_DATA DacCtrl[0xFF];
byte DacCtrlMap[0xFF]; byte DacCtrlUsed;
int DacCtrlTime[0xFF]; byte DacCtrlUsg[0xFF];
void ** dac_control; DACCTRL_DATA DacCtrl[0xFF];
byte DacCtrlMap[0xFF];
void dac_control_grow(byte chip_id); int DacCtrlTime[0xFF];
void ** dac_control;
int dac_control_recursion;
void dac_control_grow(byte chip_id);
int run_dac_control( int time );
int dac_control_recursion;
public:
void chip_reg_write(unsigned Sample, byte ChipType, byte ChipID, byte Port, byte Offset, byte Data); int run_dac_control( int time );
// Implementation public:
public: void chip_reg_write(unsigned Sample, byte ChipType, byte ChipID, byte Port, byte Offset, byte Data);
Vgm_Core();
~Vgm_Core(); // Implementation
public:
protected: Vgm_Core();
virtual blargg_err_t load_mem_( byte const [], int ); ~Vgm_Core();
private: protected:
// blip_time_t // PSG clocks virtual blargg_err_t load_mem_( byte const [], int );
typedef int vgm_time_t; // 44100 per second, REGARDLESS of sample rate
typedef int fm_time_t; // FM sample count private:
// blip_time_t // PSG clocks
int sample_rate; typedef int vgm_time_t; // 44100 per second, REGARDLESS of sample rate
int vgm_rate; // rate of log, 44100 normally, adjusted by tempo typedef int fm_time_t; // FM sample count
double fm_rate; // FM samples per second
int sample_rate;
header_t _header; int vgm_rate; // rate of log, 44100 normally, adjusted by tempo
double fm_rate; // FM samples per second
// VGM to FM time
int fm_time_factor; header_t _header;
int fm_time_offset;
fm_time_t to_fm_time( vgm_time_t ) const; // VGM to FM time
int fm_time_factor;
// VGM to PSG time int fm_time_offset;
int blip_time_factor; fm_time_t to_fm_time( vgm_time_t ) const;
blip_time_t to_psg_time( vgm_time_t ) const;
// VGM to PSG time
int blip_ay_time_factor; int blip_time_factor;
int ay_time_offset; blip_time_t to_psg_time( vgm_time_t ) const;
blip_time_t to_ay_time( vgm_time_t ) const;
int blip_ay_time_factor;
int blip_huc6280_time_factor; int ay_time_offset;
int huc6280_time_offset; blip_time_t to_ay_time( vgm_time_t ) const;
blip_time_t to_huc6280_time( vgm_time_t ) const;
int blip_huc6280_time_factor;
// Current time and position in log int huc6280_time_offset;
vgm_time_t vgm_time; blip_time_t to_huc6280_time( vgm_time_t ) const;
byte const* pos;
byte const* loop_begin; int blip_gbdmg_time_factor;
bool has_looped; int gbdmg_time_offset;
blip_time_t to_gbdmg_time( vgm_time_t ) const;
// PCM
enum { PCM_BANK_COUNT = 0x40 }; // Current time and position in log
typedef struct _vgm_pcm_bank_data vgm_time_t vgm_time;
{ byte const* pos;
unsigned DataSize; byte const* loop_begin;
byte* Data; bool has_looped;
unsigned DataStart;
} VGM_PCM_DATA; // PCM
typedef struct _vgm_pcm_bank enum { PCM_BANK_COUNT = 0x40 };
{ typedef struct _vgm_pcm_bank_data
unsigned BankCount; {
VGM_PCM_DATA* Bank; unsigned DataSize;
unsigned DataSize; byte* Data;
byte* Data; unsigned DataStart;
unsigned DataPos; } VGM_PCM_DATA;
unsigned BnkPos; typedef struct _vgm_pcm_bank
} VGM_PCM_BANK; {
unsigned BankCount;
typedef struct pcmbank_table VGM_PCM_DATA* Bank;
{ unsigned DataSize;
byte ComprType; byte* Data;
byte CmpSubType; unsigned DataPos;
byte BitDec; unsigned BnkPos;
byte BitCmp; } VGM_PCM_BANK;
unsigned EntryCount;
void* Entries; typedef struct pcmbank_table
} PCMBANK_TBL; {
byte ComprType;
VGM_PCM_BANK PCMBank[PCM_BANK_COUNT]; byte CmpSubType;
PCMBANK_TBL PCMTbl; byte BitDec;
byte BitCmp;
void ReadPCMTable(unsigned DataSize, const byte* Data); unsigned EntryCount;
void AddPCMData(byte Type, unsigned DataSize, const byte* Data); void* Entries;
bool DecompressDataBlk(VGM_PCM_DATA* Bank, unsigned DataSize, const byte* Data); } PCMBANK_TBL;
const byte* GetPointerFromPCMBank(byte Type, unsigned DataPos);
VGM_PCM_BANK PCMBank[PCM_BANK_COUNT];
byte const* pcm_pos; // current position in PCM data PCMBANK_TBL PCMTbl;
int dac_amp[2];
int dac_disabled[2]; // -1 if disabled void ReadPCMTable(unsigned DataSize, const byte* Data);
void write_pcm( vgm_time_t, int chip, int amp ); void AddPCMData(byte Type, unsigned DataSize, const byte* Data);
bool DecompressDataBlk(VGM_PCM_DATA* Bank, unsigned DataSize, const byte* Data);
blip_time_t run( vgm_time_t ); const byte* GetPointerFromPCMBank(byte Type, unsigned DataPos);
int run_ym2151( int chip, int time );
int run_ym2203( int chip, int time ); byte const* pcm_pos; // current position in PCM data
int run_ym2413( int chip, int time ); int dac_amp[2];
int run_ym2612( int chip, int time ); int dac_disabled[2]; // -1 if disabled
int run_ym3812( int chip, int time ); void write_pcm( vgm_time_t, int chip, int amp );
int run_ymf262( int chip, int time );
int run_ym2610( int chip, int time ); blip_time_t run( vgm_time_t );
int run_ym2608( int chip, int time ); int run_ym2151( int chip, int time );
int run_ymz280b( int time ); int run_ym2203( int chip, int time );
int run_c140( int time ); int run_ym2413( int chip, int time );
int run_segapcm( int time ); int run_ym2612( int chip, int time );
int run_rf5c68( int time ); int run_ym3812( int chip, int time );
int run_rf5c164( int time ); int run_ymf262( int chip, int time );
int run_pwm( int time ); int run_ym2610( int chip, int time );
int run_okim6258( int chip, int time ); int run_ym2608( int chip, int time );
int run_okim6295( int chip, int time ); int run_ymz280b( int time );
int run_k051649( int time ); int run_c140( int time );
int run_k053260( int time ); int run_segapcm( int time );
int run_k054539( int time ); int run_rf5c68( int time );
int run_qsound( int chip, int time ); int run_rf5c164( int time );
void update_fm_rates( int* ym2151_rate, int* ym2413_rate, int* ym2612_rate ) const; int run_pwm( int time );
}; int run_okim6258( int chip, int time );
int run_okim6295( int chip, int time );
#endif int run_k051649( int time );
int run_k053260( int time );
int run_k054539( int time );
int run_qsound( int chip, int time );
void update_fm_rates( int* ym2151_rate, int* ym2413_rate, int* ym2612_rate ) const;
};
#endif

File diff suppressed because it is too large Load Diff