view src/echo_plugin/echo.c @ 984:df7b09989aee trunk

[svn] - We got a new plugin, captain! - FileWriter is the ultimate plugin for dumping audio to files. It should be the successor of Disk Writer and Out-Lame, as it supports the same output formats as those (WAVE and MP3). The main advantage of having only one file dumping plugin for many formats is that not every plugin has to think about file handling (where to write files to, how to call them etc.) that much anymore. - FileWriter is also very extensible - adding new output formats should be very easy.
author mf0102
date Mon, 30 Apr 2007 14:16:32 -0700
parents d124034ebea3
children 8ca72224786a
line wrap: on
line source

#include <audacious/plugin.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>
#include <audacious/i18n.h>
#include "audacious/configdb.h"
#include "echo.h"

#include "../../config.h"

static void init(void);
static void cleanup(void);
static int mod_samples(gpointer * d, gint length, AFormat afmt, gint srate, gint nch);

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

EffectPlugin echo_ep =
{
	NULL,
	NULL,
	NULL, /* Description */
	init,
	cleanup,
	echo_about,
	echo_configure,
	mod_samples,
	NULL
};

static gint16 *buffer = NULL;
gint echo_delay = 500, echo_feedback = 50, echo_volume = 50;
gboolean echo_surround_enable = FALSE;
static int w_ofs;

EffectPlugin *get_eplugin_info(void)
{
	echo_ep.description = g_strdup_printf(_("Echo Plugin %s"), VERSION);
	return &echo_ep;
}

static void init(void)
{
	ConfigDb *cfg;
	
	if (sizeof(short) != sizeof(gint16))
		abort();

	cfg = bmp_cfg_db_open();
	bmp_cfg_db_get_int(cfg, "echo_plugin", "delay", &echo_delay);
	bmp_cfg_db_get_int(cfg, "echo_plugin", "feedback", &echo_feedback);
	bmp_cfg_db_get_int(cfg, "echo_plugin", "volume", &echo_volume);
	bmp_cfg_db_get_bool(cfg, "echo_plugin", "enable_surround", &echo_surround_enable);
	bmp_cfg_db_close(cfg);
}

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

static int mod_samples(gpointer * d, gint length, AFormat afmt, gint srate, gint nch)
{
	gint i, in, out, buf, r_ofs, fb_div;
	gint16 *data = (gint16 *) * d;
	static gint old_srate, old_nch;

	if (!(afmt == FMT_S16_NE ||
	      (afmt == FMT_S16_LE && G_BYTE_ORDER == G_LITTLE_ENDIAN) ||
	      (afmt == FMT_S16_BE && G_BYTE_ORDER == G_BIG_ENDIAN)))
		return length;

	if (!buffer)
		buffer = g_malloc0(BUFFER_BYTES + 2);

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

	if (echo_surround_enable && nch == 2)
		fb_div = 200;
	else
		fb_div = 100;

	r_ofs = w_ofs - (srate * echo_delay / 1000) * nch;
	if (r_ofs < 0)
		r_ofs += BUFFER_SHORTS;

	for (i = 0; i < length / BYTES_PS; i++)
	{
		in = data[i];
		buf = buffer[r_ofs];
		if (echo_surround_enable && nch == 2)
		{
			if (i & 1)
				buf -= buffer[r_ofs - 1];
			else
				buf -= buffer[r_ofs + 1];
		}
		out = in + buf * echo_volume / 100;
		buf = in + buf * echo_feedback / fb_div;
		out = CLAMP(out, -32768, 32767);
		buf = CLAMP(buf, -32768, 32767);
		buffer[w_ofs] = buf;
		data[i] = out;
		if (++r_ofs >= BUFFER_SHORTS)
			r_ofs -= BUFFER_SHORTS;
		if (++w_ofs >= BUFFER_SHORTS)
			w_ofs -= BUFFER_SHORTS;
	}

	return length;
}