1 // Common interface to game music file emulators
2 
3 // Game_Music_Emu 0.6.0
4 #ifndef MUSIC_EMU_H
5 #define MUSIC_EMU_H
6 
7 #include "Gme_File.h"
8 class Multi_Buffer;
9 
10 struct Music_Emu : public Gme_File {
11 public:
12 // Basic functionality (see Gme_File.h for file loading/track info functions)
13 
14 	// Set output sample rate. Must be called only once before loading file.
15 	blargg_err_t set_sample_rate( long sample_rate );
16 
17 	// Start a track, where 0 is the first track. Also clears warning string.
18 	blargg_err_t start_track( int );
19 
20 	// Generate 'count' samples info 'buf'. Output is in stereo. Any emulation
21 	// errors set warning string, and major errors also end track.
22 	typedef short sample_t;
23 	blargg_err_t play( long count, sample_t* buf );
24 
25 // Informational
26 
27 	// Sample rate sound is generated at
28 	long sample_rate() const;
29 
30 	// Index of current track or -1 if one hasn't been started
31 	int current_track() const;
32 
33 	// Number of voices used by currently loaded file
34 	int voice_count() const;
35 
36 	// Names of voices
37 	const char** voice_names() const;
38 
39 // Track status/control
40 
41 	// Number of milliseconds (1000 msec = 1 second) played since beginning of track
42 	long tell() const;
43 
44 	// Number of samples generated since beginning of track
45 	long tell_samples() const;
46 
47 	// Seek to new time in track. Seeking backwards or far forward can take a while.
48 	blargg_err_t seek( long msec );
49 
50 	// Equivalent to restarting track then skipping n samples
51 	blargg_err_t seek_samples( long n );
52 
53 	// Skip n samples
54 	blargg_err_t skip( long n );
55 
56 	// True if a track has reached its end
57 	bool track_ended() const;
58 
59 	// Set start time and length of track fade out. Once fade ends track_ended() returns
60 	// true. Fade time can be changed while track is playing.
61 	void set_fade( long start_msec, long length_msec = 8000 );
62 
63 	// Disable automatic end-of-track detection and skipping of silence at beginning
64 	void ignore_silence( bool disable = true );
65 
66 	// Info for current track
67 	using Gme_File::track_info;
68 	blargg_err_t track_info( track_info_t* out ) const;
69 
70 // Sound customization
71 
72 	// Adjust song tempo, where 1.0 = normal, 0.5 = half speed, 2.0 = double speed.
73 	// Track length as returned by track_info() assumes a tempo of 1.0.
74 	void set_tempo( double );
75 
76 	// Mute/unmute voice i, where voice 0 is first voice
77 	void mute_voice( int index, bool mute = true );
78 
79 	// Set muting state of all voices at once using a bit mask, where -1 mutes them all,
80 	// 0 unmutes them all, 0x01 mutes just the first voice, etc.
81 	void mute_voices( int mask );
82 
83 	// Change overall output amplitude, where 1.0 results in minimal clamping.
84 	// Must be called before set_sample_rate().
85 	void set_gain( double );
86 
87 	// Request use of custom multichannel buffer. Only supported by "classic" emulators;
88 	// on others this has no effect. Should be called only once *before* set_sample_rate().
set_bufferMusic_Emu89 	virtual void set_buffer( Multi_Buffer* ) { }
90 
91 	// Enables/disables accurate emulation options, if any are supported. Might change
92 	// equalizer settings.
93 	void enable_accuracy( bool enable = true );
94 
95 // Sound equalization (treble/bass)
96 
97 	// Frequency equalizer parameters (see gme.txt)
98 	// See gme.h for definition of struct gme_equalizer_t.
99 	typedef gme_equalizer_t equalizer_t;
100 
101 	// Current frequency equalizater parameters
102 	equalizer_t const& equalizer() const;
103 
104 	// Set frequency equalizer parameters
105 	void set_equalizer( equalizer_t const& );
106 
107 	// Construct equalizer of given treble/bass settings
make_equalizerMusic_Emu108 	static const equalizer_t make_equalizer( double treble, double bass )
109 	{
110 	    const Music_Emu::equalizer_t e = { treble, bass,
111 		0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
112 	    return e;
113 	}
114 
115 	// Equalizer settings for TV speaker
116 	static equalizer_t const tv_eq;
117 
118 public:
119 	Music_Emu();
120 	~Music_Emu();
121 protected:
set_max_initial_silenceMusic_Emu122 	void set_max_initial_silence( int n )       { max_initial_silence = n; }
set_silence_lookaheadMusic_Emu123 	void set_silence_lookahead( int n )         { silence_lookahead = n; }
set_voice_countMusic_Emu124 	void set_voice_count( int n )               { voice_count_ = n; }
125 	void set_voice_names( const char* const* names );
set_track_endedMusic_Emu126 	void set_track_ended()                      { emu_track_ended_ = true; }
gainMusic_Emu127 	double gain() const                         { return gain_; }
tempoMusic_Emu128 	double tempo() const                        { return tempo_; }
129 	void remute_voices();
130 
131 	virtual blargg_err_t set_sample_rate_( long sample_rate ) = 0;
set_equalizer_Music_Emu132 	virtual void set_equalizer_( equalizer_t const& ) { }
enable_accuracy_Music_Emu133 	virtual void enable_accuracy_( bool /* enable */ ) { }
134 	virtual void mute_voices_( int mask ) = 0;
135 	virtual void set_tempo_( double ) = 0;
136 	virtual blargg_err_t start_track_( int ) = 0; // tempo is set before this
137 	virtual blargg_err_t play_( long count, sample_t* out ) = 0;
138 	virtual blargg_err_t skip_( long count );
139 protected:
140 	virtual void unload();
141 	virtual void pre_load();
142 	virtual void post_load_();
143 private:
144 	// general
145 	equalizer_t equalizer_;
146 	int max_initial_silence;
147 	const char** voice_names_;
148 	int voice_count_;
149 	int mute_mask_;
150 	double tempo_;
151 	double gain_;
152 
153 	long sample_rate_;
154 	blargg_long msec_to_samples( blargg_long msec ) const;
155 
156 	// track-specific
157 	int current_track_;
158 	blargg_long out_time;  // number of samples played since start of track
159 	blargg_long emu_time;  // number of samples emulator has generated since start of track
160 	bool emu_track_ended_; // emulator has reached end of track
161 	volatile bool track_ended_;
162 	void clear_track_vars();
163 	void end_track_if_error( blargg_err_t );
164 
165 	// fading
166 	blargg_long fade_start;
167 	int fade_step;
168 	void handle_fade( long count, sample_t* out );
169 
170 	// silence detection
171 	int silence_lookahead; // speed to run emulator when looking ahead for silence
172 	bool ignore_silence_;
173 	long silence_time;     // number of samples where most recent silence began
174 	long silence_count;    // number of samples of silence to play before using buf
175 	long buf_remain;       // number of samples left in silence buffer
176 	enum { buf_size = 2048 };
177 	blargg_vector<sample_t> buf;
178 	void fill_buf();
179 	void emu_play( long count, sample_t* out );
180 
181 	Multi_Buffer* effects_buffer;
182 	friend Music_Emu* gme_new_emu( gme_type_t, int );
183 	friend void gme_set_stereo_depth( Music_Emu*, double );
184 };
185 
186 // base class for info-only derivations
187 struct Gme_Info_ : Music_Emu
188 {
189 	virtual blargg_err_t set_sample_rate_( long sample_rate );
190 	virtual void set_equalizer_( equalizer_t const& );
191 	virtual void enable_accuracy_( bool );
192 	virtual void mute_voices_( int mask );
193 	virtual void set_tempo_( double );
194 	virtual blargg_err_t start_track_( int );
195 	virtual blargg_err_t play_( long count, sample_t* out );
196 	virtual void pre_load();
197 	virtual void post_load_();
198 };
199 
track_info(track_info_t * out)200 inline blargg_err_t Music_Emu::track_info( track_info_t* out ) const
201 {
202 	return track_info( out, current_track_ );
203 }
204 
sample_rate()205 inline long Music_Emu::sample_rate() const          { return sample_rate_; }
voice_names()206 inline const char** Music_Emu::voice_names() const  { return voice_names_; }
voice_count()207 inline int Music_Emu::voice_count() const           { return voice_count_; }
current_track()208 inline int Music_Emu::current_track() const         { return current_track_; }
track_ended()209 inline bool Music_Emu::track_ended() const          { return track_ended_; }
equalizer()210 inline const Music_Emu::equalizer_t& Music_Emu::equalizer() const { return equalizer_; }
211 
enable_accuracy(bool b)212 inline void Music_Emu::enable_accuracy( bool b )    { enable_accuracy_( b ); }
set_tempo_(double t)213 inline void Music_Emu::set_tempo_( double t )       { tempo_ = t; }
remute_voices()214 inline void Music_Emu::remute_voices()              { mute_voices( mute_mask_ ); }
ignore_silence(bool b)215 inline void Music_Emu::ignore_silence( bool b )     { ignore_silence_ = b; }
start_track_(int)216 inline blargg_err_t Music_Emu::start_track_( int )  { return 0; }
217 
set_voice_names(const char * const * names)218 inline void Music_Emu::set_voice_names( const char* const* names )
219 {
220 	// Intentional removal of const, so users don't have to remember obscure const in middle
221 	voice_names_ = const_cast<const char**> (names);
222 }
223 
mute_voices_(int)224 inline void Music_Emu::mute_voices_( int ) { }
225 
set_gain(double g)226 inline void Music_Emu::set_gain( double g )
227 {
228 	assert( !sample_rate() ); // you must set gain before setting sample rate
229 	gain_ = g;
230 }
231 
232 #endif
233