// Sega Master System/Mark III, Sega Genesis/Mega Drive, BBC Micro VGM music file emulator // Game_Music_Emu 0.5.5 #ifndef VGM_EMU_H #define VGM_EMU_H #include "blargg_common.h" #include "blargg_source.h" #include "resampler.h" #include "multi_buffer.h" #include "ym2413_emu.h" #include "ym2612_emu.h" #include "sms_apu.h" typedef short sample_t; typedef int vgm_time_t; typedef int fm_time_t; enum { fm_time_bits = 12 }; enum { blip_time_bits = 12 }; enum { buf_size = 2048 }; // VGM header format enum { header_size = 0x40 }; struct header_t { char tag [4]; byte data_size [4]; byte version [4]; byte psg_rate [4]; byte ym2413_rate [4]; byte gd3_offset [4]; byte track_duration [4]; byte loop_offset [4]; byte loop_duration [4]; byte frame_rate [4]; byte noise_feedback [2]; byte noise_width; byte unused1; byte ym2612_rate [4]; byte ym2151_rate [4]; byte data_offset [4]; byte unused2 [8]; }; enum { gme_max_field = 63 }; struct track_info_t { /* times in milliseconds; -1 if unknown */ long length; long intro_length; long loop_length; /* empty string if not available */ char game [64]; char song [96]; char author [64]; }; // Emulates VGM music using SN76489/SN76496 PSG, YM2612, and YM2413 FM sound chips. // Supports custom sound buffer and frequency equalization when VGM uses just the PSG. // FM sound chips can be run at their proper rates, or slightly higher to reduce // aliasing on high notes. Currently YM2413 support requires that you supply a // YM2413 sound chip emulator. I can provide one I've modified to work with the library. struct Vgm_Emu { double fm_rate; long psg_rate; long vgm_rate; bool disable_oversampling; long fm_time_offset; int fm_time_factor; int blip_time_factor; byte const* file_begin; byte const* file_end; vgm_time_t vgm_time; byte const* loop_begin; byte const* pos; byte const* pcm_data; byte const* pcm_pos; int dac_amp; int dac_disabled; // -1 if disabled struct Blip_Buffer* blip_buf; // general long clock_rate_; unsigned buf_changed_count; int max_initial_silence; int voice_count; int mute_mask_; int tempo; double gain; long sample_rate; // track-specific blargg_long out_time; // number of samples played since start of track blargg_long emu_time; // number of samples emulator has generated since start of track bool emu_track_ended_; // emulator has reached end of track volatile bool track_ended; // fading blargg_long fade_start; int fade_step; // silence detection int silence_lookahead; // speed to run emulator when looking ahead for silence bool ignore_silence; long silence_time; // number of samples where most recent silence began long silence_count; // number of samples of silence to play before using buf long buf_remain; // number of samples left in silence buffer // larger items at the end struct track_info_t info; sample_t buf_ [buf_size]; struct Ym2612_Emu ym2612; struct Ym2413_Emu ym2413; struct Sms_Apu psg; struct Blip_Synth pcm; struct Stereo_Buffer stereo_buf; struct Resampler resampler; struct Stereo_Buffer buf; }; void Vgm_init( struct Vgm_Emu* this ); // Disable running FM chips at higher than normal rate. Will result in slightly // more aliasing of high notes. static inline void Vgm_disable_oversampling( struct Vgm_Emu* this, bool disable ) { this->disable_oversampling = disable; } // Header for currently loaded file static inline struct header_t *header( struct Vgm_Emu* this ) { return (struct header_t*) this->file_begin; } // Basic functionality (see Gme_File.h for file loading/track info functions) blargg_err_t Vgm_load_mem( struct Vgm_Emu* this, byte const* new_data, long new_size, bool parse_info ); // True if any FM chips are used by file. Always false until init_fm() // is called. static inline bool uses_fm( struct Vgm_Emu* this ) { return Ym2612_enabled( &this->ym2612 ) || Ym2413_enabled( &this->ym2413 ); } // Set output sample rate. Must be called only once before loading file. blargg_err_t Vgm_set_sample_rate( struct Vgm_Emu* this, long sample_rate ); // Start a track, where 0 is the first track. Also clears warning string. blargg_err_t Vgm_start_track( struct Vgm_Emu* this ); // Generate 'count' samples info 'buf'. Output is in stereo. Any emulation // errors set warning string, and major errors also end track. blargg_err_t Vgm_play( struct Vgm_Emu* this, long count, sample_t* buf ) ICODE_ATTR; // Track status/control // Number of milliseconds (1000 msec = 1 second) played since beginning of track long Track_tell( struct Vgm_Emu* this ); // Seek to new time in track. Seeking backwards or far forward can take a while. blargg_err_t Track_seek( struct Vgm_Emu* this, long msec ); // Skip n samples blargg_err_t Track_skip( struct Vgm_Emu* this, long n ); // Set start time and length of track fade out. Once fade ends track_ended() returns // true. Fade time can be changed while track is playing. void Track_set_fade( struct Vgm_Emu* this, long start_msec, long length_msec ); // Get track length in milliseconds static inline long Track_get_length( struct Vgm_Emu* this ) { long length = this->info.length; if ( length <= 0 ) { length = this->info.intro_length + 2 * this->info.loop_length; // intro + 2 loops if ( length <= 0 ) length = 150 * 1000; // 2.5 minutes } return length; } // Sound customization // Adjust song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed. // Track length as returned by track_info() assumes a tempo of 1.0. void Sound_set_tempo( struct Vgm_Emu* this, int t ); // Mute/unmute voice i, where voice 0 is first voice void Sound_mute_voice( struct Vgm_Emu* this, int index, bool mute ); // Set muting state of all voices at once using a bit mask, where -1 mutes them all, // 0 unmutes them all, 0x01 mutes just the first voice, etc. void Sound_mute_voices( struct Vgm_Emu* this, int mask ); // Change overall output amplitude, where 1.0 results in minimal clamping. // Must be called before set_sample_rate(). static inline void Sound_set_gain( struct Vgm_Emu* this, double g ) { assert( !this->sample_rate ); // you must set gain before setting sample rate this->gain = g; } #endif