summaryrefslogtreecommitdiff
path: root/plugins/gme/game-music-emu-0.5.5/gme/Music_Emu.h
blob: c5f1d029548487de7b12e4c6f880b9eb6dc25ee2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// Common interface to game music file emulators

// Game_Music_Emu 0.5.5
#ifndef MUSIC_EMU_H
#define MUSIC_EMU_H

#include "Gme_File.h"
class Multi_Buffer;

struct Music_Emu : public Gme_File {
public:
// Basic functionality (see Gme_File.h for file loading/track info functions)

	// Set output sample rate. Must be called only once before loading file.
	blargg_err_t set_sample_rate( long sample_rate );
	
	// Start a track, where 0 is the first track. Also clears warning string.
	blargg_err_t start_track( int );
	
	// Generate 'count' samples info 'buf'. Output is in stereo. Any emulation
	// errors set warning string, and major errors also end track.
	typedef short sample_t;
	blargg_err_t play( long count, sample_t* buf );
	
// Informational
	
	// Sample rate sound is generated at
	long sample_rate() const;
	
	// Index of current track or -1 if one hasn't been started
	int current_track() const;
	
	// Number of voices used by currently loaded file
	int voice_count() const;
	
	// Names of voices
	const char** voice_names() const;
	
// Track status/control

	// Number of milliseconds (1000 msec = 1 second) played since beginning of track
	long tell() const;
	
	// Seek to new time in track. Seeking backwards or far forward can take a while.
	blargg_err_t seek( long msec );
	
	// Skip n samples
	blargg_err_t skip( long n );
	
	// True if a track has reached its end
	bool track_ended() const;
	
	// 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 set_fade( long start_msec, long length_msec = 8000 );
	
	// Disable automatic end-of-track detection and skipping of silence at beginning
	void ignore_silence( bool disable = true );
	
	// Info for current track
	Gme_File::track_info;
	blargg_err_t track_info( track_info_t* out ) const;
	
// 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 set_tempo( double );
	
	// Mute/unmute voice i, where voice 0 is first voice
	void mute_voice( int index, bool mute = true );
	
	// 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 mute_voices( int mask );
	
	// Change overall output amplitude, where 1.0 results in minimal clamping.
	// Must be called before set_sample_rate().
	void set_gain( double );
	
	// Request use of custom multichannel buffer. Only supported by "classic" emulators;
	// on others this has no effect. Should be called only once *before* set_sample_rate().
	virtual void set_buffer( Multi_Buffer* ) { }
	
// Sound equalization (treble/bass)

	// Frequency equalizer parameters (see gme.txt)
	// See gme.h for definition of struct gme_equalizer_t.
	typedef gme_equalizer_t equalizer_t;
	
	// Current frequency equalizater parameters
	equalizer_t const& equalizer() const;
	
	// Set frequency equalizer parameters
	void set_equalizer( equalizer_t const& );
	
	// Equalizer settings for TV speaker
	static equalizer_t const tv_eq;
	
public:
	Music_Emu();
	~Music_Emu();
protected:
	void set_max_initial_silence( int n )       { max_initial_silence = n; }
	void set_silence_lookahead( int n )         { silence_lookahead = n; }
	void set_voice_count( int n )               { voice_count_ = n; }
	void set_voice_names( const char* const* names );
	void set_track_ended()                      { emu_track_ended_ = true; }
	double gain() const                         { return gain_; }
	double tempo() const                        { return tempo_; }
	void remute_voices();
	
	virtual blargg_err_t set_sample_rate_( long sample_rate ) = 0;
	virtual void set_equalizer_( equalizer_t const& ) { };
	virtual void mute_voices_( int mask ) = 0;
	virtual void set_tempo_( double ) = 0;
	virtual blargg_err_t start_track_( int ) = 0; // tempo is set before this
	virtual blargg_err_t play_( long count, sample_t* out ) = 0;
	virtual blargg_err_t skip_( long count );
protected:
	virtual void unload();
	virtual void pre_load();
	virtual void post_load_();
private:
	// general
	equalizer_t equalizer_;
	int max_initial_silence;
	const char** voice_names_;
	int voice_count_;
	int mute_mask_;
	double tempo_;
	double gain_;
	
	long sample_rate_;
	blargg_long msec_to_samples( blargg_long msec ) const;
	
	// track-specific
	int current_track_;
	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_;
	void clear_track_vars();
	void end_track_if_error( blargg_err_t );
	
	// fading
	blargg_long fade_start;
	int fade_step;
	void handle_fade( long count, sample_t* out );
	
	// 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
	enum { buf_size = 2048 };
	blargg_vector<sample_t> buf;
	void fill_buf();
	void emu_play( long count, sample_t* out );
	
	Multi_Buffer* effects_buffer;
	friend Music_Emu* gme_new_emu( gme_type_t, int );
	friend void gme_set_stereo_depth( Music_Emu*, double );
};

// base class for info-only derivations
struct Gme_Info_ : Music_Emu
{
	virtual blargg_err_t set_sample_rate_( long sample_rate );
	virtual void set_equalizer_( equalizer_t const& );
	virtual void mute_voices_( int mask );
	virtual void set_tempo_( double );
	virtual blargg_err_t start_track_( int );
	virtual blargg_err_t play_( long count, sample_t* out );
	virtual void pre_load();
	virtual void post_load_();
};

inline blargg_err_t Music_Emu::track_info( track_info_t* out ) const
{
	return track_info( out, current_track_ );
}

inline long Music_Emu::sample_rate() const          { return sample_rate_; }
inline const char** Music_Emu::voice_names() const  { return voice_names_; }
inline int Music_Emu::voice_count() const           { return voice_count_; }
inline int Music_Emu::current_track() const         { return current_track_; }
inline bool Music_Emu::track_ended() const          { return track_ended_; }
inline const Music_Emu::equalizer_t& Music_Emu::equalizer() const { return equalizer_; }

inline void Music_Emu::set_tempo_( double t )       { tempo_ = t; }
inline void Music_Emu::remute_voices()              { mute_voices( mute_mask_ ); }
inline void Music_Emu::ignore_silence( bool b )     { ignore_silence_ = b; }
inline blargg_err_t Music_Emu::start_track_( int )  { return 0; }

inline void Music_Emu::set_voice_names( const char* const* names )
{
	// Intentional removal of const, so users don't have to remember obscure const in middle
	voice_names_ = const_cast<const char**> (names);
}

inline void Music_Emu::mute_voices_( int ) { }

inline void Music_Emu::set_gain( double g )
{
	assert( !sample_rate() ); // you must set gain before setting sample rate
	gain_ = g;
}

#endif