1 // Multi-channel effects buffer with echo and individual panning for each channel
2 
3 // Game_Music_Emu $vers
4 #ifndef EFFECTS_BUFFER_H
5 #define EFFECTS_BUFFER_H
6 
7 #include "Multi_Buffer.h"
8 
9 // See Simple_Effects_Buffer (below) for a simpler interface
10 
11 class Effects_Buffer : public Multi_Buffer {
12 public:
13 	// To reduce memory usage, fewer buffers can be used (with a best-fit
14 	// approach if there are too few), and maximum echo delay can be reduced
15 	Effects_Buffer( int max_bufs = 32, int echo_size = 24 * 1024 );
16 
17 	struct pan_vol_t
18 	{
19 		float vol; // 0.0 = silent, 0.5 = half volume, 1.0 = normal
20 		float pan; // -1.0 = left, 0.0 = center, +1.0 = right
21 	};
22 
23 	// Global configuration
24 	struct config_t
25 	{
26 		bool enabled; // false = disable all effects
27 
28 		// Current sound is echoed at adjustable left/right delay,
29 		// with reduced treble and volume (feedback).
30 		float treble;   // 1.0 = full treble, 0.1 = very little, 0.0 = silent
31 		int delay [2];  // left, right delays (msec)
32 		float feedback; // 0.0 = no echo, 0.5 = each echo half previous, 1.0 = cacophony
33 		pan_vol_t side_chans [2]; // left and right side channel volume and pan
34 	};
config()35 	config_t& config() { return config_; }
36 
37 	// Limits of delay (msec)
38 	int min_delay() const;
39 	int max_delay() const;
40 
41 	// Per-channel configuration. Two or more channels with matching parameters are
42 	// optimized to internally use the same buffer.
43 	struct chan_config_t : pan_vol_t
44 	{
45 		// (inherited from pan_vol_t)
46 		//float vol;        // these only affect center channel
47 		//float pan;
48 		bool surround;  // if true, negates left volume to put sound in back
49 		bool echo;      // false = channel doesn't have any echo
50 	};
chan_config(int i)51 	chan_config_t& chan_config( int i ) { return chans [i + extra_chans].cfg; }
52 
53 	// Applies any changes made to config() and chan_config()
54 	virtual void apply_config();
55 
56 // Implementation
57 public:
58 	~Effects_Buffer();
59 	blargg_err_t set_sample_rate( int samples_per_sec, int msec = blip_default_length );
60 	blargg_err_t set_channel_count( int, int const* = NULL );
61 	void clock_rate( int );
62 	void bass_freq( int );
63 	void clear();
64 	channel_t channel( int );
65 	void end_frame( blip_time_t );
66 	int read_samples( blip_sample_t [], int );
samples_avail()67 	int samples_avail() const { return (bufs [0].samples_avail() - mixer.samples_read) * 2; }
68 	enum { stereo = 2 };
69 	typedef int fixed_t;
70 
71 protected:
72 	enum { extra_chans = stereo * stereo };
73 
74 private:
75 	config_t config_;
76 	int clock_rate_;
77 	int bass_freq_;
78 
79 	int echo_size;
80 
81 	struct chan_t
82 	{
83 		fixed_t vol [stereo];
84 		chan_config_t cfg;
85 		channel_t channel;
86 	};
87 	blargg_vector<chan_t> chans;
88 
89 	struct buf_t : Tracked_Blip_Buffer
90 	{
91 		// nasty: Blip_Buffer has something called fixed_t
92 		Effects_Buffer::fixed_t vol [stereo];
93 		bool echo;
94 
newbuf_t95 		void* operator new ( size_t, void* p ) { return p; }
deletebuf_t96 		void operator delete ( void* ) { }
97 
~buf_tbuf_t98 		~buf_t() { }
99 	};
100 	buf_t* bufs;
101 	int bufs_size;
102 	int bufs_max; // bufs_size <= bufs_max, to limit memory usage
103 	Stereo_Mixer mixer;
104 
105 	struct {
106 		int delay [stereo];
107 		fixed_t treble;
108 		fixed_t feedback;
109 		fixed_t low_pass [stereo];
110 	} s;
111 
112 	blargg_vector<fixed_t> echo;
113 	int echo_pos;
114 
115 	bool no_effects;
116 	bool no_echo;
117 
118 	void assign_buffers();
119 	void clear_echo();
120 	void mix_effects( blip_sample_t out [], int pair_count );
121 	blargg_err_t new_bufs( int size );
122 	void delete_bufs();
123 };
124 
125 // Simpler interface and lower memory usage
126 class Simple_Effects_Buffer : public Effects_Buffer {
127 public:
128 	struct config_t
129 	{
130 		bool enabled;   // false = disable all effects
131 
132 		float echo;     // 0.0 = none, 1.0 = lots
133 		float stereo;   // 0.0 = channels in center, 1.0 = channels on left/right
134 		bool surround;  // true = put some channels in back
135 	};
config()136 	config_t& config() { return config_; }
137 
138 	// Applies any changes made to config()
139 	void apply_config();
140 
141 // Implementation
142 public:
143 	Simple_Effects_Buffer();
144 private:
145 	config_t config_;
146 	void chan_config(); // hide
147 };
148 
149 #endif
150