Updated Game_Music_Emu to support Game Boy DMG sound in VGM files
parent
0290c1a3dd
commit
4acbb21f99
|
@ -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 = ®s [wave_ram - io_addr];
|
wave.wave_ram = ®s [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 )
|
||||||
|
|
|
@ -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& );
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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
|
@ -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
Loading…
Reference in New Issue