#include <stdlib.h>
#include <string.h>

#include <audacious/i18n.h>
#include <audacious/misc.h>
#include <audacious/plugin.h>
#include <audacious/preferences.h>

#include "config.h"

#define MAX_DELAY 1000
#define MAX_SRATE 50000
#define MAX_CHANNELS 2
#define BYTES_PS sizeof(float)
#define BUFFER_SAMPLES (MAX_SRATE * MAX_DELAY / 1000)
#define BUFFER_SHORTS (BUFFER_SAMPLES * MAX_CHANNELS)
#define BUFFER_BYTES (BUFFER_SHORTS * BYTES_PS)

static const char * const echo_defaults[] = {
 "delay", "500",
 "feedback", "50",
 "volume", "50",
 NULL};

static const PreferencesWidget echo_widgets[] = {
 {WIDGET_LABEL, N_("<b>Echo</b>")},
 {WIDGET_SPIN_BTN, N_("Delay:"),
  .cfg_type = VALUE_INT, .csect = "echo_plugin", .cname = "delay",
  .data = {.spin_btn = {0, MAX_DELAY, 10, N_("ms")}}},
 {WIDGET_SPIN_BTN, N_("Feedback:"),
  .cfg_type = VALUE_INT, .csect = "echo_plugin", .cname = "feedback",
  .data = {.spin_btn = {0, 100, 1, "%"}}},
 {WIDGET_SPIN_BTN, N_("Volume:"),
  .cfg_type = VALUE_INT, .csect = "echo_plugin", .cname = "volume",
  .data = {.spin_btn = {0, 100, 1, "%"}}}};

static const PluginPreferences echo_prefs = {
 .widgets = echo_widgets,
 .n_widgets = sizeof echo_widgets / sizeof echo_widgets[0]};

static float *buffer = NULL;
static int w_ofs;

static bool_t init (void)
{
	aud_config_set_defaults ("echo_plugin", echo_defaults);
	return TRUE;
}

static void cleanup(void)
{
	free(buffer);
	buffer = NULL;
}

static int echo_channels = 0;
static int echo_rate = 0;

static void echo_start(int *channels, int *rate)
{
	static int old_srate, old_nch;

	if (buffer == NULL)
		buffer = malloc (BUFFER_BYTES);

	echo_channels = *channels;
	echo_rate = *rate;

	if (echo_channels != old_nch || echo_rate != old_srate)
	{
		memset(buffer, 0, BUFFER_BYTES);
		w_ofs = 0;
		old_nch = echo_channels;
		old_srate = echo_rate;
	}
}

static void echo_process(float **d, int *samples)
{
	int delay = aud_get_int ("echo_plugin", "delay");
	int feedback = aud_get_int ("echo_plugin", "feedback");
	int volume = aud_get_int ("echo_plugin", "volume");

	float in, out, buf;
	int r_ofs;
	float *data = *d;
	float *end = *d + *samples;

	r_ofs = w_ofs - (echo_rate * delay / 1000) * echo_channels;
	if (r_ofs < 0)
		r_ofs += BUFFER_SHORTS;

	for (; data < end; data++)
	{
		in = *data;

		buf = buffer[r_ofs];
		out = in + buf * volume / 100;
		buf = in + buf * feedback / 100;
		buffer[w_ofs] = buf;
		*data = out;

		if (++r_ofs >= BUFFER_SHORTS)
			r_ofs -= BUFFER_SHORTS;
		if (++w_ofs >= BUFFER_SHORTS)
			w_ofs -= BUFFER_SHORTS;
	}
}

static void echo_finish(float **d, int *samples)
{
	echo_process(d, samples);
}

static const char echo_about[] =
 "Echo Plugin\n"
 "By Johan Levin, 1999\n\n"
 "Surround echo by Carl van Schaik, 1999";

AUD_EFFECT_PLUGIN
(
	.name = N_("Echo"),
	.domain = PACKAGE,
	.about_text = echo_about,
	.prefs = & echo_prefs,
	.init = init,
	.cleanup = cleanup,
	.start = echo_start,
	.process = echo_process,
	.finish = echo_finish,
	.preserves_format = TRUE
)
