// Multi-channel effects buffer with echo and individual panning for each channel
// Game_Music_Emu $vers
#ifndef EFFECTS_BUFFER_H
#define EFFECTS_BUFFER_H
#include <vector>
#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, long echo_size = 24 * 1024L);
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 this->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 this->chans[i + extra_chans].cfg; }
// Apply any changes made to config() and chan_config()
virtual void apply_config();
~Effects_Buffer();
blargg_err_t set_sample_rate(long samples_per_sec, int msec = blip_default_length);
blargg_err_t set_channel_count(int, const int * = nullptr);
void clock_rate(long);
void bass_freq(int);
void clear();
channel_t channel(int);
void end_frame(blip_time_t);
long read_samples(blip_sample_t *, long);
long samples_avail() const { return (this->bufs[0]->samples_avail() - this->mixer.samples_read) * 2; }
enum { stereo = 2 };
typedef int32_t fixed_t;
protected:
enum { extra_chans = stereo * stereo };
private:
config_t config_;
long clock_rate_;
int bass_freq_;
int32_t echo_size;
struct chan_t
{
fixed_t vol [stereo];
chan_config_t cfg;
channel_t channel;
};
std::vector<chan_t> chans;
struct buf_t : Tracked_Blip_Buffer
{
fixed_t vol[stereo];
bool echo;
};
std::vector<std::unique_ptr<buf_t>> bufs;
int bufs_size;
int bufs_max; // bufs_size <= bufs_max, to limit memory usage
Stereo_Mixer mixer;
struct
{
long delay[stereo];
fixed_t treble;
fixed_t feedback;
fixed_t low_pass[stereo];
} s;
std::vector<fixed_t> echo;
int32_t 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 this->config_; }
// Apply any changes made to config()
void apply_config();
public:
Simple_Effects_Buffer();
private:
config_t config_;
void chan_config(); // hide
};
#endif