cog/Frameworks/GME/gme/Vgm_Core.h

347 lines
11 KiB
C++

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