/* * XMP plugin for XMMS * Written by Claudio Matsuoka , 2000-04-30 * Based on J. Nick Koston's MikMod plugin * * $Id: plugin.c,v 1.4 2001/01/07 00:53:15 claudio Exp $ */ #include "xmp-plugin.h" #include "xmms/configfile.h" #include "xmms/util.h" #include #include "xmp.h" #include "xmpi.h" #include "driver.h" #include "formats.h" static void init (void); static int is_our_file (char *); static void play_file (char *); static int get_time (void); static void stop(void); static void *play_loop (void *); static void mod_pause (short); static void seek (int time); static void aboutbox (void); static void get_song_info (char *, char **, int *); static void configure (void); static void config_ok (GtkWidget *, gpointer); static void file_info_box (char *); static struct xmp_control ctl; static pthread_t decode_thread; static pthread_mutex_t load_mutex = PTHREAD_MUTEX_INITIALIZER; XMPConfig xmp_cfg; extern gboolean xmp_xmms_audio_error; extern InputPlugin xmp_ip; extern struct xmp_ord_info xxo_info[XMP_DEF_MAXORD]; /* module parameters */ gboolean xmp_going = 0; static GtkWidget *Res_16; static GtkWidget *Res_8; static GtkWidget *Chan_ST; static GtkWidget *Chan_MO; static GtkWidget *Sample_44; static GtkWidget *Sample_22; static GtkWidget *Sample_11; static GtkWidget *Convert_Check; static GtkWidget *Fixloops_Check; static GtkWidget *Modrange_Check; static GtkWidget *Interp_Check; static GtkWidget *Filter_Check; static GtkObject *pansep_adj; static GtkWidget *xmp_conf_window = NULL; static GtkWidget *about_window = NULL; InputPlugin xmp_ip = { NULL, /* handle */ NULL, /* filename */ "XMP Player " VERSION, /* description */ init, /* init */ aboutbox, /* about */ configure, /* configure */ is_our_file, /* is_our_file */ NULL, /* scan_dir */ play_file, /* play_file */ stop, /* stop */ mod_pause, /* pause */ seek, /* seek */ NULL, /* set_eq */ get_time, /* get_time */ NULL, /* get_volume */ NULL, /* set_volume */ NULL, /* add_vis -- obsolete */ NULL, /* get_vis_type -- obsolete */ NULL, /* add_vis_pcm */ NULL, /* set_info */ NULL, /* set_info_text */ get_song_info, /* get_song_info */ file_info_box, /* file_info_box */ NULL /* output */ }; static void aboutbox () { GtkWidget *dialog_vbox1; GtkWidget *hbox1; GtkWidget *label1; GtkWidget *dialog_action_area1; GtkWidget *about_exit; if (about_window) { gdk_window_raise(about_window->window); return; } about_window = gtk_dialog_new(); gtk_object_set_data(GTK_OBJECT(about_window), "about_window", about_window); gtk_window_set_title(GTK_WINDOW(about_window), "About xmp plugin"); gtk_window_set_policy(GTK_WINDOW(about_window), FALSE, FALSE, FALSE); gtk_window_set_position(GTK_WINDOW(about_window), GTK_WIN_POS_MOUSE); gtk_signal_connect(GTK_OBJECT(about_window), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed), &about_window); gtk_container_border_width(GTK_CONTAINER(about_window), 10); dialog_vbox1 = GTK_DIALOG(about_window)->vbox; gtk_object_set_data(GTK_OBJECT(about_window), "dialog_vbox1", dialog_vbox1); gtk_widget_show(dialog_vbox1); gtk_container_border_width(GTK_CONTAINER(dialog_vbox1), 5); hbox1 = gtk_hbox_new(FALSE, 0); gtk_object_set_data(GTK_OBJECT(about_window), "hbox1", hbox1); gtk_widget_show(hbox1); gtk_box_pack_start(GTK_BOX(dialog_vbox1), hbox1, TRUE, TRUE, 0); gtk_container_border_width(GTK_CONTAINER(hbox1), 5); gtk_widget_realize(about_window); label1 = gtk_label_new( "Extended Module Player " VERSION "\n" "http://xmp.helllabs.org\n" "Written by Claudio Matsuoka \n" "and Hipolito Carraro Jr. " "\n\nWARNING: This plugin is experimental. Please\n" "report bugs to xmp-bugs@helllabs.org" ); gtk_object_set_data(GTK_OBJECT(about_window), "label1", label1); gtk_widget_show(label1); gtk_box_pack_start(GTK_BOX(hbox1), label1, TRUE, TRUE, 0); dialog_action_area1 = GTK_DIALOG(about_window)->action_area; gtk_object_set_data(GTK_OBJECT(about_window), "dialog_action_area1", dialog_action_area1); gtk_widget_show(dialog_action_area1); gtk_container_border_width(GTK_CONTAINER(dialog_action_area1), 10); about_exit = gtk_button_new_with_label("Ok"); gtk_signal_connect_object(GTK_OBJECT(about_exit), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(about_window)); gtk_object_set_data(GTK_OBJECT(about_window), "about_exit", about_exit); gtk_widget_show(about_exit); gtk_box_pack_start(GTK_BOX(dialog_action_area1), about_exit, TRUE, TRUE, 0); gtk_widget_show(about_window); } static void stop (void) { if (!xmp_going) return; _D("*** stop!"); xmp_stop_module (); pthread_join (decode_thread, NULL); } static void seek (int time) { int i, t; _D("seek to %d, total %d", time, xmp_cfg.time); time *= 1000; for (i = 0; i < xmp_cfg.mod_info.len; i++) { t = xxo_info[i].time; _D("%2d: %d %d\n", i, time, t); if (t > time) { int a; if (i > 0) i--; a = xmp_ord_set (i); xmp_ip.output->flush (xxo_info[i].time); break; } } } static void mod_pause (short p) { xmp_ip.output->pause(p); } static int get_time (void) { if (xmp_xmms_audio_error) return -2; if (!xmp_going) return -1; return xmp_ip.output->output_time(); } InputPlugin *get_iplugin_info (void) { return &xmp_ip; } static void init(void) { ConfigFile *cfg; gchar *filename; xmp_cfg.mixing_freq = 0; xmp_cfg.convert8bit = 0; xmp_cfg.fixloops = 0; xmp_cfg.modrange = 0; xmp_cfg.force8bit = 0; xmp_cfg.force_mono = 0; xmp_cfg.interpolation = TRUE; xmp_cfg.filter = TRUE; xmp_cfg.pan_amplitude = 80; #define CFGREADINT(x) xmms_cfg_read_int (cfg, "XMP", #x, &xmp_cfg.x) filename = g_strconcat(g_get_home_dir(), "/.xmms/config", NULL); if ((cfg = xmms_cfg_open_file(filename))) { CFGREADINT (mixing_freq); CFGREADINT (force8bit); CFGREADINT (convert8bit); CFGREADINT (modrange); CFGREADINT (fixloops); CFGREADINT (force_mono); CFGREADINT (interpolation); CFGREADINT (filter); CFGREADINT (pan_amplitude); xmms_cfg_free(cfg); } xmp_drv_register (&drv_xmms); xmp_init_formats (); memset (&ctl, 0, sizeof (struct xmp_control)); xmp_event_callback = NULL; xmp_drv_mutelloc (64); } static int is_our_file (char *filename) { int i; /* Checking files by extension is braindead, we should check * by file magic instead. But the xmp interface is also braindead * in the point that it doesn't allow us to load a module while * the audio device isn't selected. Yuck. * * Additionally, xmp 2.0 can't load a module while another module * is playing, so it can't check if the module is valid or not. * In this case, we'll blindly accept the file. */ if (xmp_going) return 1; pthread_mutex_lock (&load_mutex); ctl.maxvoc = 16; ctl.drv_id = "xmms_mix"; ctl.verbose = 0; ctl.memavl = 0; xmp_drv_set (&ctl); _D("checking: %s", filename); i = xmp_load_module (filename) >= 0; _D(" returned %d", i); pthread_mutex_unlock (&load_mutex); return i; } static void get_song_info(char *filename, char **title, int *length) { char *x; /* Ugh. xmp doesn't allow me to load and scan a module while * playing. Must fix this. */ _D("song_info: %s", filename); if ((x = strrchr (filename, '/'))) filename = ++x; *title = g_strdup (filename); } static void play_file(char *filename) { struct xmp_module_info mi; int channelcnt = 1; int format = FMT_U8; FILE *f; char *info; _D("play_file: %s", filename); stop (); /* sanity check */ if(!(f = fopen(filename,"rb"))) { xmp_going = 0; return; } fclose(f); xmp_xmms_audio_error = FALSE; xmp_going = 1; ctl.resol = 8; ctl.verbose = 0; ctl.drv_id = "xmms_mix"; switch (xmp_cfg.mixing_freq) { case 1: ctl.freq = 22050; /* 1:2 mixing freq */ break; case 2: ctl.freq = 11025; /* 1:4 mixing freq */ break; default: ctl.freq = 44100; /* standard mixing freq */ break; } if ((xmp_cfg.force8bit == 0)) { format = FMT_S16_NE; ctl.resol = 16; } if ((xmp_cfg.force_mono == 0)) { channelcnt = 2; } else { ctl.outfmt |= XMP_FMT_MONO; } if ((xmp_cfg.interpolation == 1)) ctl.flags |= XMP_CTL_ITPT; if ((xmp_cfg.filter == 1)) ctl.flags |= XMP_CTL_FILTER; ctl.mix = xmp_cfg.pan_amplitude; xmp_cfg.time = xmpi_scan_module (); pthread_mutex_lock (&load_mutex); xmp_open_audio (&ctl); if (xmp_load_module (filename) < 0) { xmp_ip.set_info_text("Error loading mod"); xmp_going = 0; return; } xmp_get_module_info (&mi); memcpy (&xmp_cfg.mod_info, &mi, sizeof (mi)); pthread_mutex_unlock (&load_mutex); info = malloc (strlen (mi.name) + strlen (mi.type) + 20); sprintf (info, "%s [%s, %d ch]", mi.name, mi.type, mi.chn); xmp_ip.set_info(info, xmp_cfg.time, 128 * 1000, ctl.freq, channelcnt); free (info); _D("--- pthread_create"); pthread_create(&decode_thread, NULL, play_loop, NULL); return; } static void *play_loop (void *arg) { xmp_play_module (); xmp_close_audio (); xmp_going = 0; _D("--- pthread_exit"); pthread_exit(NULL); return NULL; } static void configure() { GtkWidget *notebook1; GtkWidget *vbox; GtkWidget *vbox1; GtkWidget *hbox1; GtkWidget *Resolution_Frame; GtkWidget *vbox4; GSList *resolution_group = NULL; GtkWidget *Channels_Frame; GtkWidget *vbox5; GSList *vbox5_group = NULL; GtkWidget *Downsample_Frame; GtkWidget *vbox3; GSList *sample_group = NULL; GtkWidget *vbox6; GtkWidget *Quality_Label; GtkWidget *Options_Label; GtkWidget *pansep_label, *pansep_hscale; GtkWidget *bbox; GtkWidget *ok; GtkWidget *cancel; if (xmp_conf_window) { gdk_window_raise(xmp_conf_window->window); return; } xmp_conf_window = gtk_window_new(GTK_WINDOW_DIALOG); gtk_object_set_data(GTK_OBJECT(xmp_conf_window), "xmp_conf_window", xmp_conf_window); gtk_window_set_title(GTK_WINDOW(xmp_conf_window), "XMP Configuration"); gtk_window_set_policy(GTK_WINDOW(xmp_conf_window), FALSE, FALSE, FALSE); gtk_window_set_position(GTK_WINDOW(xmp_conf_window), GTK_WIN_POS_MOUSE); gtk_signal_connect(GTK_OBJECT(xmp_conf_window), "destroy", GTK_SIGNAL_FUNC(gtk_widget_destroyed),&xmp_conf_window); gtk_container_border_width(GTK_CONTAINER(xmp_conf_window), 10); vbox = gtk_vbox_new(FALSE, 10); gtk_container_add(GTK_CONTAINER(xmp_conf_window), vbox); notebook1 = gtk_notebook_new(); gtk_object_set_data(GTK_OBJECT(xmp_conf_window),"notebook1", notebook1); gtk_widget_show(notebook1); gtk_box_pack_start(GTK_BOX(vbox), notebook1, TRUE, TRUE, 0); gtk_container_border_width(GTK_CONTAINER(notebook1), 3); vbox1 = gtk_vbox_new(FALSE, 0); gtk_object_set_data(GTK_OBJECT(xmp_conf_window),"vbox1", vbox1); gtk_widget_show(vbox1); hbox1 = gtk_hbox_new(FALSE, 0); gtk_object_set_data(GTK_OBJECT(xmp_conf_window),"hbox1", hbox1); gtk_widget_show(hbox1); gtk_box_pack_start(GTK_BOX(vbox1), hbox1, TRUE, TRUE, 0); Resolution_Frame = gtk_frame_new("Resolution"); gtk_object_set_data(GTK_OBJECT(xmp_conf_window), "Resolution_Frame", Resolution_Frame); gtk_widget_show(Resolution_Frame); gtk_box_pack_start(GTK_BOX(hbox1), Resolution_Frame, TRUE, TRUE, 0); gtk_container_set_border_width(GTK_CONTAINER (Resolution_Frame), 5); vbox4 = gtk_vbox_new(FALSE, 0); gtk_object_set_data(GTK_OBJECT(xmp_conf_window),"vbox4", vbox4); gtk_widget_show(vbox4); gtk_container_add(GTK_CONTAINER(Resolution_Frame), vbox4); Res_16 = gtk_radio_button_new_with_label(resolution_group, "16 bit"); resolution_group = gtk_radio_button_group(GTK_RADIO_BUTTON(Res_16)); gtk_object_set_data(GTK_OBJECT(xmp_conf_window), "Res_16", Res_16); gtk_widget_show(Res_16); gtk_box_pack_start(GTK_BOX(vbox4), Res_16, TRUE, TRUE, 0); if (xmp_cfg.force8bit == 0) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(Res_16), TRUE); Res_8 = gtk_radio_button_new_with_label(resolution_group, "8 bit"); resolution_group = gtk_radio_button_group(GTK_RADIO_BUTTON(Res_8)); gtk_object_set_data(GTK_OBJECT(xmp_conf_window), "Res_8", Res_8); gtk_widget_show(Res_8); gtk_box_pack_start(GTK_BOX(vbox4), Res_8, TRUE, TRUE, 0); if (xmp_cfg.force8bit == 1) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(Res_8), TRUE); Channels_Frame = gtk_frame_new("Channels"); gtk_object_set_data(GTK_OBJECT(xmp_conf_window), "Channels_Frame", Channels_Frame); gtk_widget_show(Channels_Frame); gtk_box_pack_start(GTK_BOX(hbox1), Channels_Frame, TRUE, TRUE, 0); gtk_container_set_border_width(GTK_CONTAINER(Channels_Frame), 5); vbox5 = gtk_vbox_new(FALSE, 0); gtk_object_set_data(GTK_OBJECT(xmp_conf_window), "vbox5", vbox5); gtk_widget_show(vbox5); gtk_container_add(GTK_CONTAINER(Channels_Frame), vbox5); Chan_ST = gtk_radio_button_new_with_label(vbox5_group, "Stereo"); vbox5_group = gtk_radio_button_group(GTK_RADIO_BUTTON(Chan_ST)); gtk_object_set_data(GTK_OBJECT(xmp_conf_window), "Chan_ST", Chan_ST); gtk_widget_show(Chan_ST); gtk_box_pack_start(GTK_BOX(vbox5), Chan_ST, TRUE, TRUE, 0); if (xmp_cfg.force_mono == 0) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(Chan_ST), TRUE); Chan_MO = gtk_radio_button_new_with_label(vbox5_group, "Mono"); vbox5_group = gtk_radio_button_group(GTK_RADIO_BUTTON(Chan_MO)); gtk_object_set_data(GTK_OBJECT(xmp_conf_window), "Chan_MO", Chan_MO); gtk_widget_show(Chan_MO); gtk_box_pack_start(GTK_BOX(vbox5), Chan_MO, TRUE, TRUE, 0); if (xmp_cfg.force_mono == 1) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(Chan_MO), TRUE); Downsample_Frame = gtk_frame_new("Sampling rate"); gtk_object_set_data(GTK_OBJECT(xmp_conf_window), "Downsample_Frame", Downsample_Frame); gtk_widget_show(Downsample_Frame); gtk_box_pack_start(GTK_BOX(vbox1), Downsample_Frame, TRUE, TRUE, 0); gtk_container_set_border_width(GTK_CONTAINER(Downsample_Frame), 5); vbox3 = gtk_vbox_new(FALSE, 0); gtk_object_set_data(GTK_OBJECT(xmp_conf_window), "vbox3", vbox3); gtk_widget_show(vbox3); gtk_container_add(GTK_CONTAINER(Downsample_Frame), vbox3); Sample_44 = gtk_radio_button_new_with_label(sample_group, "44 kHz"); sample_group = gtk_radio_button_group(GTK_RADIO_BUTTON(Sample_44)); gtk_object_set_data(GTK_OBJECT(xmp_conf_window),"Sample_44", Sample_44); gtk_widget_show(Sample_44); gtk_box_pack_start(GTK_BOX(vbox3), Sample_44, TRUE, TRUE, 0); if (xmp_cfg.mixing_freq == FREQ_SAMPLE_44) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(Sample_44),TRUE); Sample_22 = gtk_radio_button_new_with_label(sample_group, "22 kHz)"); sample_group = gtk_radio_button_group(GTK_RADIO_BUTTON(Sample_22)); gtk_object_set_data(GTK_OBJECT(xmp_conf_window), "Sample_22",Sample_22); gtk_widget_show(Sample_22); gtk_box_pack_start(GTK_BOX(vbox3), Sample_22, TRUE, TRUE, 0); if (xmp_cfg.mixing_freq == FREQ_SAMPLE_22) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(Sample_22),TRUE); Sample_11 = gtk_radio_button_new_with_label(sample_group, "11 kHz"); sample_group = gtk_radio_button_group(GTK_RADIO_BUTTON(Sample_11)); gtk_object_set_data(GTK_OBJECT(xmp_conf_window), "Sample_11",Sample_11); gtk_widget_show(Sample_11); gtk_box_pack_start(GTK_BOX(vbox3), Sample_11, TRUE, TRUE, 0); if (xmp_cfg.mixing_freq == FREQ_SAMPLE_11) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(Sample_11),TRUE); vbox6 = gtk_vbox_new(FALSE, 0); gtk_object_set_data(GTK_OBJECT(xmp_conf_window), "vbox6", vbox6); gtk_widget_show(vbox6); /* Options */ #define OPTCHECK(w,l,o) { \ w = gtk_check_button_new_with_label(l); \ gtk_object_set_data(GTK_OBJECT(xmp_conf_window), #w, w); \ gtk_widget_show(w); \ gtk_box_pack_start(GTK_BOX(vbox6), w, TRUE, TRUE, 0); \ if (xmp_cfg.o == 1) \ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), TRUE); \ } OPTCHECK(Convert_Check, "Convert 16 bit samples to 8 bit", convert8bit); OPTCHECK(Fixloops_Check, "Fix sample loops", fixloops); OPTCHECK(Modrange_Check, "Force 3 octave range in standard MOD files", modrange); OPTCHECK(Interp_Check, "Enable 32-bit linear interpolation", interpolation); OPTCHECK(Filter_Check, "Enable IT filters", filter); pansep_label = gtk_label_new("Pan amplitude (%)"); gtk_widget_show(pansep_label); gtk_box_pack_start(GTK_BOX(vbox6), pansep_label, TRUE, TRUE, 0); pansep_adj = gtk_adjustment_new(xmp_cfg.pan_amplitude, 0.0, 100.0, 1.0, 10.0, 1.0); pansep_hscale = gtk_hscale_new(GTK_ADJUSTMENT(pansep_adj)); gtk_scale_set_digits(GTK_SCALE(pansep_hscale), 0); gtk_scale_set_draw_value(GTK_SCALE(pansep_hscale), TRUE); gtk_scale_set_value_pos(GTK_SCALE(pansep_hscale), GTK_POS_BOTTOM); gtk_widget_show(pansep_hscale); gtk_box_pack_start(GTK_BOX(vbox6), pansep_hscale, TRUE, TRUE, 0); Quality_Label = gtk_label_new("Quality"); gtk_object_set_data(GTK_OBJECT(xmp_conf_window), "Quality_Label", Quality_Label); gtk_widget_show(Quality_Label); gtk_notebook_append_page(GTK_NOTEBOOK(notebook1), vbox1, Quality_Label); Options_Label = gtk_label_new("Options"); gtk_object_set_data(GTK_OBJECT(xmp_conf_window), "Options_Label", Options_Label); gtk_widget_show(Options_Label); gtk_notebook_append_page(GTK_NOTEBOOK(notebook1), vbox6, Options_Label); bbox = gtk_hbutton_box_new(); gtk_button_box_set_layout(GTK_BUTTON_BOX(bbox), GTK_BUTTONBOX_END); gtk_button_box_set_spacing(GTK_BUTTON_BOX(bbox), 5); gtk_box_pack_start(GTK_BOX(vbox), bbox, FALSE, FALSE, 0); ok = gtk_button_new_with_label("Ok"); gtk_signal_connect(GTK_OBJECT(ok), "clicked", GTK_SIGNAL_FUNC(config_ok), NULL); GTK_WIDGET_SET_FLAGS(ok, GTK_CAN_DEFAULT); gtk_box_pack_start(GTK_BOX(bbox), ok, TRUE, TRUE, 0); gtk_widget_show(ok); gtk_widget_grab_default(ok); cancel = gtk_button_new_with_label("Cancel"); gtk_signal_connect_object(GTK_OBJECT(cancel), "clicked", GTK_SIGNAL_FUNC(gtk_widget_destroy), GTK_OBJECT(xmp_conf_window)); GTK_WIDGET_SET_FLAGS(cancel, GTK_CAN_DEFAULT); gtk_box_pack_start(GTK_BOX(bbox), cancel, TRUE, TRUE, 0); gtk_widget_show(cancel); gtk_widget_show(bbox); gtk_widget_show(vbox); gtk_widget_show(xmp_conf_window); } static void config_ok (GtkWidget *widget, gpointer data) { ConfigFile *cfg; gchar *filename; if (GTK_TOGGLE_BUTTON(Res_16)->active) xmp_cfg.force8bit = 0; if (GTK_TOGGLE_BUTTON(Res_8)->active) xmp_cfg.force8bit = 1; if (GTK_TOGGLE_BUTTON(Chan_ST)->active) xmp_cfg.force_mono = 0; if (GTK_TOGGLE_BUTTON(Chan_MO)->active) xmp_cfg.force_mono = 1; if (GTK_TOGGLE_BUTTON(Sample_44)->active) xmp_cfg.mixing_freq = 0; if (GTK_TOGGLE_BUTTON(Sample_22)->active) xmp_cfg.mixing_freq = 1; if (GTK_TOGGLE_BUTTON(Sample_11)->active) xmp_cfg.mixing_freq = 2; xmp_cfg.interpolation = !!GTK_TOGGLE_BUTTON(Interp_Check)->active; xmp_cfg.filter = !!GTK_TOGGLE_BUTTON(Filter_Check)->active; xmp_cfg.convert8bit = !!GTK_TOGGLE_BUTTON(Convert_Check)->active; xmp_cfg.modrange = !!GTK_TOGGLE_BUTTON(Modrange_Check)->active; xmp_cfg.fixloops = !!GTK_TOGGLE_BUTTON(Fixloops_Check)->active; xmp_cfg.pan_amplitude = (guchar)GTK_ADJUSTMENT(pansep_adj)->value; ctl.mix = xmp_cfg.pan_amplitude; filename = g_strconcat(g_get_home_dir(), "/.xmms/config", NULL); cfg = xmms_cfg_open_file(filename); if (!cfg) cfg = xmms_cfg_new(); #define CFGWRITEINT(x) xmms_cfg_write_int (cfg, "XMP", #x, xmp_cfg.x) CFGWRITEINT (mixing_freq); CFGWRITEINT (force8bit); CFGWRITEINT (convert8bit); CFGWRITEINT (modrange); CFGWRITEINT (fixloops); CFGWRITEINT (force_mono); CFGWRITEINT (interpolation); CFGWRITEINT (filter); CFGWRITEINT (pan_amplitude); xmms_cfg_write_file(cfg, filename); xmms_cfg_free(cfg); g_free(filename); gtk_widget_destroy(xmp_conf_window); } static void file_info_box (char *filename) { }