summaryrefslogtreecommitdiff
path: root/plugins/gme/game-music-emu-0.6pre/gme/Effects_Buffer.h
blob: 348c74c780c9b934b6a321372af9e0e6cd9ca493 (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
// Multi-channel effects buffer with echo and individual panning for each channel

// Game_Music_Emu 0.6-pre
#ifndef EFFECTS_BUFFER_H
#define EFFECTS_BUFFER_H

#include "Multi_Buffer.h"

// See Simple_Effects_Buffer (below) for a simpler interface

class Effects_Buffer : public Multi_Buffer {
public:
	// To reduce memory usage, fewer buffers can be used (with a best-fit
	// approach if there are too few), and maximum echo delay can be reduced
	Effects_Buffer( int max_bufs = 32, int echo_size = 24 * 1024 );
	
	struct pan_vol_t
	{
		float vol; // 0.0 = silent, 0.5 = half volume, 1.0 = normal
		float pan; // -1.0 = left, 0.0 = center, +1.0 = right
	};
	
	// Global configuration
	struct config_t
	{
		bool enabled; // false = disable all effects
		
		// Current sound is echoed at adjustable left/right delay,
		// with reduced treble and volume (feedback). 
		float treble;   // 1.0 = full treble, 0.1 = very little, 0.0 = silent
		int delay [2];  // left, right delays (msec)
		float feedback; // 0.0 = no echo, 0.5 = each echo half previous, 1.0 = cacophony
		pan_vol_t side_chans [2]; // left and right side channel volume and pan
	};
	config_t& config() { return config_; }
	
	// Limits of delay (msec)
	int min_delay() const;
	int max_delay() const;
	
	// Per-channel configuration. Two or more channels with matching parameters are
	// optimized to internally use the same buffer.
	struct chan_config_t : pan_vol_t
	{
		// (inherited from pan_vol_t)
		//float vol;        // these only affect center channel
		//float pan;
		bool surround;  // if true, negates left volume to put sound in back
		bool echo;      // false = channel doesn't have any echo
	};
	chan_config_t& chan_config( int i ) { return chans [i + extra_chans].cfg; }
	
	// Applies any changes made to config() and chan_config()
	virtual void apply_config();
	
// Implementation
public:
	~Effects_Buffer();
	blargg_err_t set_sample_rate( int samples_per_sec, int msec = blip_default_length );
	blargg_err_t set_channel_count( int, int const* = NULL );
	void clock_rate( int );
	void bass_freq( int );
	void clear();
	channel_t channel( int );
	void end_frame( blip_time_t );
	int read_samples( blip_sample_t [], int );
	int samples_avail() const { return (bufs [0].samples_avail() - mixer.samples_read) * 2; }
	enum { stereo = 2 };
	typedef int fixed_t;

protected:
	enum { extra_chans = stereo * stereo };

private:
	config_t config_;
	int clock_rate_;
	int bass_freq_;
	
	int echo_size;
	
	struct chan_t
	{
		fixed_t vol [stereo];
		chan_config_t cfg;
		channel_t channel;
	};
	blargg_vector<chan_t> chans;
	
	struct buf_t : Tracked_Blip_Buffer
	{
		// nasty: Blip_Buffer has something called fixed_t
		Effects_Buffer::fixed_t vol [stereo];
		bool echo;
		
		void* operator new ( size_t, void* p ) { return p; }
		void operator delete ( void* ) { }
		
		~buf_t() { }
	};
	buf_t* bufs;
	int bufs_size;
	int bufs_max; // bufs_size <= bufs_max, to limit memory usage
	Stereo_Mixer mixer;
	
	struct {
		int delay [stereo];
		fixed_t treble;
		fixed_t feedback;
		fixed_t low_pass [stereo];
	} s;
	
	blargg_vector<fixed_t> echo;
	int echo_pos;
	
	bool no_effects;
	bool no_echo;
	
	void assign_buffers();
	void clear_echo();
	void mix_effects( blip_sample_t out [], int pair_count );
	blargg_err_t new_bufs( int size );
	void delete_bufs();
};

// Simpler interface and lower memory usage
class Simple_Effects_Buffer : public Effects_Buffer {
public:
	struct config_t
	{
		bool enabled;   // false = disable all effects
		
		float echo;     // 0.0 = none, 1.0 = lots
		float stereo;   // 0.0 = channels in center, 1.0 = channels on left/right
		bool surround;  // true = put some channels in back
	};
	config_t& config() { return config_; }
	
	// Applies any changes made to config()
	void apply_config();
	
// Implementation
public:
	Simple_Effects_Buffer();
private:
	config_t config_;
	void chan_config(); // hide
};

#endif