/* exampleecho.c: Example echo plugin for XMMS. Note that this plugin is very simple and doesn't allow for much customization. See the echo.c in the XMMS tarball for a better echo plugin. exampleecho: simple XMMS echo plugin, made as an example. Copyright (C) 2006 Kumar Appaiah This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #define ECHO_SCALE 0.4 void about(void); void query(AFormat *afmt, gint *s_rate, gint *n_channels); void init(void); void cleanup(void); void configure(void); gint mod_samples(gpointer * d, gint length, AFormat afmt, gint srate, gint nch); /* The plugin details for XMMS. */ EffectPlugin e_plugin = { NULL, NULL, "Example Echo plugin", init, cleanup, about, configure, mod_samples, query}; EffectPlugin * get_eplugin_info(void) { return &e_plugin; } #define BUFFER_LENGTH 16384 /* For about 0.37 seconds delay */ /* Buffers: used as circular buffers. */ static gfloat *buffer_left = NULL; static gfloat *buffer_right = NULL; /* Circular buffer indices. */ static guint left_index = 0; static guint right_index = 0; static char *about_text = "An example echo plugin"; void about(void) { static GtkWidget *about_dialog = NULL; if (about_dialog != NULL) return; /* Convenient function for dialog boxes */ about_dialog = xmms_show_message("About Example Echo Plugin", about_text, "Ok", FALSE, NULL, NULL); gtk_signal_connect(GTK_OBJECT(about_dialog), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &about_dialog); } void query(AFormat *afmt, gint *s_rate, gint *n_channels) { *afmt = FMT_S16_LE; *s_rate = 44100; *n_channels = 2; } void init(void) { if (buffer_left == NULL) { buffer_left = g_malloc0(sizeof(gfloat) * BUFFER_LENGTH); } if (buffer_right == NULL) { buffer_right = g_malloc0(sizeof(gfloat) * BUFFER_LENGTH); } } void cleanup(void) { g_free(buffer_left); buffer_left = NULL; g_free(buffer_right); buffer_right = NULL; } void configure(void) { /* Configuration dialog box goes here. */ } gint mod_samples(gpointer * d, gint length, AFormat afmt, gint srate, gint nch) { /* Read data as 16 bit values */ gint16 *data = (gint16 *) * d; gint i; /* We have "length" bytes, so "length / 2" samples */ for (i = 0; i < length / 2; i += 2) { gfloat echo_val; /* For the left sample */ echo_val = buffer_left[left_index]; /* Retrieve delayed value */ buffer_left[left_index++] = data[i]; /* Store latest sample */ data[i] = (1 - ECHO_SCALE) * data[i] + ECHO_SCALE * echo_val; /* Set the echoed value */ left_index = left_index % BUFFER_LENGTH; /* Circular buffer shift */ /* Do the same for the right channel samples */ echo_val = buffer_right[right_index]; /* Retrieve delayed value */ buffer_right[right_index++] = data[i + 1]; /* Store latest sample */ data[i + 1] = (1 - ECHO_SCALE) * data[i + 1] + ECHO_SCALE * echo_val; /* Set the echoed value */ right_index = right_index % BUFFER_LENGTH; /* Circular buffer shift */ } return length; /* Amount of data we have processed. */ }