Mercurial > audlegacy-plugins
view src/crossfade/cfgutil.c @ 3167:9739ba93fd79
alsa-ng: Don't try to join threads that have already exited.
author | William Pitcock <nenolod@atheme.org> |
---|---|
date | Fri, 15 May 2009 00:05:17 -0500 |
parents | de2f796d6f04 |
children |
line wrap: on
line source
/* * XMMS Crossfade Plugin * Copyright (C) 2000-2007 Peter Eisenlohr <peter@eisenlohr.org> * * based on the original OSS Output Plugin * Copyright (C) 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas, Thomas Nilsson and 4Front Technologies * * 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. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #undef PRESET_SUPPORT #include "crossfade.h" #include "configure.h" #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> # define ConfigFile ConfigDb # define xmms_cfg_read_int aud_cfg_db_get_int # define xmms_cfg_read_string aud_cfg_db_get_string # define xmms_cfg_read_boolean aud_cfg_db_get_bool # define xmms_cfg_write_int aud_cfg_db_set_int # define xmms_cfg_write_string aud_cfg_db_set_string # define xmms_cfg_write_boolean aud_cfg_db_set_bool # define xmms_cfg_remove_key aud_cfg_db_unset_key # define xmms_cfg_open_default_file aud_cfg_db_open # define xmms_cfg_write_default_file aud_cfg_db_close void xmms_cfg_dummy(ConfigDb *dummy) { } # define xmms_cfg_free xmms_cfg_dummy /* init with DEFAULT_CFG to make sure all string pointers are set to NULL */ config_t _xfg = CONFIG_DEFAULT; /* also used in configure.c */ static config_t *xfg = &_xfg; /*****************************************************************************/ static void update_plugin_config(gchar **config_string, gchar *name, plugin_config_t *pc, gboolean save); static void g_free_f(gpointer data, gpointer user_data) { g_free(data); } /*****************************************************************************/ static gchar *strip(gchar *s) { gchar *p; if (!s) return NULL; for (; *s == ' '; s++); if (!*s) return s; for (p = s + strlen(s) - 1; *p == ' '; p--); *++p = 0; return s; } static void update_plugin_config(gchar **config_string, gchar *name, plugin_config_t *pc, gboolean save) { plugin_config_t default_pc = DEFAULT_OP_CONFIG; gchar *buffer = NULL; gchar out[1024]; gboolean plugin_found = FALSE; gchar *plugin, *next_plugin; gchar *args; if (pc && !save) *pc = default_pc; if (!config_string || !*config_string || !name || !pc) { DEBUG(("[crossfade] update_plugin_config: missing arg!\n")); return; } buffer = g_strdup(*config_string); out[0] = 0; for (plugin = buffer; plugin; plugin = next_plugin) { if ((next_plugin = strchr(plugin, ';'))) *next_plugin++ = 0; if ((args = strchr(plugin, '='))) *args++ = 0; plugin = strip(plugin); if (!*plugin || !args || !*args) continue; if (save) { if (strcmp(plugin, name) == 0) continue; if (*out) strcat(out, "; "); strcat(out, plugin); strcat(out, "="); strcat(out, args); continue; } else if (strcmp(plugin, name)) continue; args = strip(args); sscanf(args, "%d,%d,%d,%d", &pc->throttle_enable, &pc->max_write_enable, &pc->max_write_len, &pc->force_reopen); pc->max_write_len &= -4; plugin_found = TRUE; } if (save) { /* only save if settings differ from defaults */ if ((pc->throttle_enable != default_pc.throttle_enable) || (pc->max_write_enable != default_pc.max_write_enable) || (pc->max_write_len != default_pc.max_write_len) || (pc->force_reopen != default_pc.force_reopen)) { if (*out) strcat(out, "; "); sprintf(out + strlen(out), "%s=%d,%d,%d,%d", name, pc->throttle_enable ? 1 : 0, pc->max_write_enable ? 1 : 0, pc->max_write_len, pc->force_reopen); } if (*config_string) g_free(*config_string); *config_string = g_strdup(out); } g_free(buffer); } /*****************************************************************************/ #ifdef PRESET_SUPPORT static void scan_presets(gchar *filename) { struct stat stats; FILE *fh; gchar *data, **lines, *tmp, *name; int i; if (lstat(filename, &stats)) { DEBUG(("[crossfade] scan_presets: \"%s\":\n", filename)); PERROR("[crossfade] scan_presets: lstat"); return; } if (stats.st_size <= 0) return; if (!(data = g_malloc(stats.st_size + 1))) { DEBUG(("[crossfade] scan_presets: g_malloc(%ld) failed!\n", stats.st_size)); return; } if (!(fh = fopen(filename, "r"))) { PERROR("[crossfade] scan_presets: fopen"); g_free(data); return; } if (fread(data, stats.st_size, 1, fh) != 1) { DEBUG(("[crossfade] scan_presets: fread() failed!\n")); g_free(data); fclose(fh); return; } fclose(fh); data[stats.st_size] = 0; lines = g_strsplit(data, "\n", 0); g_free(data); if (!lines) { DEBUG(("[crossfade] scan_presets: g_strsplit() failed!\n")); return; } g_list_foreach(config->presets, g_free_f, NULL); g_list_free(config->presets); config->presets = NULL; for (i = 0; lines[i]; i++) { if (lines[i][0] == '[') { if ((tmp = strchr(lines[i], ']'))) { *tmp = 0; if ((name = g_strdup(lines[i] + 1))) config->presets = g_list_append(config->presets, name); } } } g_strfreev(lines); } #endif static void read_fade_config(ConfigFile *cfgfile, gchar *section, gchar *key, fade_config_t *fc) { gchar *s = NULL; gint n; if (!cfgfile || !section || !key || !fc) return; xmms_cfg_read_string(cfgfile, section, key, &s); if (!s) return; n = sscanf(s, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", &fc->type, &fc->pause_len_ms, &fc->simple_len_ms, &fc->out_enable, &fc->out_len_ms, &fc->out_volume, &fc->ofs_type, &fc->ofs_type_wanted, &fc->ofs_custom_ms, &fc->in_locked, &fc->in_enable, &fc->in_len_ms, &fc->in_volume, &fc->flush_pause_enable, &fc->flush_pause_len_ms, &fc->flush_in_enable, &fc->flush_in_len_ms, &fc->flush_in_volume); g_free(s); } static void write_fade_config(ConfigFile *cfgfile, gchar *section, gchar *key, fade_config_t *fc) { gchar *s; if (!cfgfile || !section || !key || !fc) return; s = g_strdup_printf("%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", fc->type, fc->pause_len_ms, fc->simple_len_ms, fc->out_enable, fc->out_len_ms, fc->out_volume, fc->ofs_type, fc->ofs_type_wanted, fc->ofs_custom_ms, fc->in_locked, fc->in_enable, fc->in_len_ms, fc->in_volume, fc->flush_pause_enable, fc->flush_pause_len_ms, fc->flush_in_enable, fc->flush_in_len_ms, fc->flush_in_volume); if (!s) return; xmms_cfg_write_string(cfgfile, section, key, s); g_free(s); } void xfade_load_config() { #ifdef PRESET_SUPPORT gchar *filename; #endif gchar *section = "Crossfade"; ConfigFile *cfgfile; if ((cfgfile = xmms_cfg_open_default_file())) { /* *INDENT-OFF* */ /* config items used in v0.1 */ xmms_cfg_read_string (cfgfile, section, "output_plugin", &config->op_name); xmms_cfg_read_string (cfgfile, section, "op_config_string", &config->op_config_string); xmms_cfg_read_int (cfgfile, section, "buffer_size", &config->mix_size_ms); xmms_cfg_read_int (cfgfile, section, "sync_size", &config->sync_size_ms); xmms_cfg_read_int (cfgfile, section, "preload_size", &config->preload_size_ms); xmms_cfg_read_int (cfgfile, section, "songchange_timeout", &config->songchange_timeout); xmms_cfg_read_boolean(cfgfile, section, "enable_mixer", &config->enable_mixer); xmms_cfg_read_boolean(cfgfile, section, "mixer_reverse", &config->mixer_reverse); xmms_cfg_read_boolean(cfgfile, section, "enable_debug", &config->enable_debug); xmms_cfg_read_boolean(cfgfile, section, "enable_monitor", &config->enable_monitor); /* config items introduced by v0.2 */ xmms_cfg_read_boolean(cfgfile, section, "gap_lead_enable", &config->gap_lead_enable); xmms_cfg_read_int (cfgfile, section, "gap_lead_len_ms", &config->gap_lead_len_ms); xmms_cfg_read_int (cfgfile, section, "gap_lead_level", &config->gap_lead_level); xmms_cfg_read_boolean(cfgfile, section, "gap_trail_enable", &config->gap_trail_enable); xmms_cfg_read_int (cfgfile, section, "gap_trail_len_ms", &config->gap_trail_len_ms); xmms_cfg_read_int (cfgfile, section, "gap_trail_level", &config->gap_trail_level); xmms_cfg_read_int (cfgfile, section, "gap_trail_locked", &config->gap_trail_locked); /* config items introduced by v0.2.1 */ xmms_cfg_read_boolean(cfgfile, section, "buffer_size_auto", &config->mix_size_auto); /* config items introduced by v0.2.3 */ xmms_cfg_read_boolean(cfgfile, section, "album_detection", &config->album_detection); /* config items introduced by v0.2.4 */ xmms_cfg_read_boolean(cfgfile, section, "http_workaround", &config->enable_http_workaround); xmms_cfg_read_boolean(cfgfile, section, "enable_op_max_used", &config->enable_op_max_used); xmms_cfg_read_int (cfgfile, section, "op_max_used_ms", &config->op_max_used_ms); /* config items introduced by v0.2.6 */ xmms_cfg_read_string (cfgfile, section, "effect_plugin", &config->ep_name); xmms_cfg_read_boolean(cfgfile, section, "effect_enable", &config->ep_enable); /* config items introduced by v0.3.0 */ xmms_cfg_read_boolean(cfgfile, section, "volnorm_enable", &config->volnorm_enable); xmms_cfg_read_boolean(cfgfile, section, "volnorm_use_qa", &config->volnorm_use_qa); xmms_cfg_read_int (cfgfile, section, "volnorm_target", &config->volnorm_target); xmms_cfg_read_boolean(cfgfile, section, "output_keep_opened", &config->output_keep_opened); xmms_cfg_read_boolean(cfgfile, section, "mixer_software", &config->mixer_software); xmms_cfg_read_int (cfgfile, section, "mixer_vol_left", &config->mixer_vol_left); xmms_cfg_read_int (cfgfile, section, "mixer_vol_right", &config->mixer_vol_right); /* config items introduced by v0.3.2 */ xmms_cfg_read_boolean(cfgfile, section, "no_xfade_if_same_file",&config->no_xfade_if_same_file); /* config items introduced by v0.3.3 */ xmms_cfg_read_boolean(cfgfile, section, "gap_crossing", &config->gap_crossing); /* fade configs */ read_fade_config(cfgfile, section, "fc_xfade", &config->fc[FADE_CONFIG_XFADE]); read_fade_config(cfgfile, section, "fc_manual", &config->fc[FADE_CONFIG_MANUAL]); read_fade_config(cfgfile, section, "fc_album", &config->fc[FADE_CONFIG_ALBUM]); read_fade_config(cfgfile, section, "fc_start", &config->fc[FADE_CONFIG_START]); read_fade_config(cfgfile, section, "fc_stop", &config->fc[FADE_CONFIG_STOP]); read_fade_config(cfgfile, section, "fc_eop", &config->fc[FADE_CONFIG_EOP]); read_fade_config(cfgfile, section, "fc_seek", &config->fc[FADE_CONFIG_SEEK]); read_fade_config(cfgfile, section, "fc_pause", &config->fc[FADE_CONFIG_PAUSE]); xmms_cfg_free(cfgfile); DEBUG(("[crossfade] load_config: configuration loaded\n")); } else DEBUG(("[crossfade] load_config: error loading config, using defaults\n")); #ifdef PRESET_SUPPORT filename = g_strconcat(g_get_home_dir(), "/.audacious/crossfade-presets", NULL); scan_presets(filename); g_free(filename); #endif } void xfade_save_config() { gchar *section = "Crossfade"; ConfigFile *cfgfile; if ((cfgfile = xmms_cfg_open_default_file())) { /* obsolete config items */ xmms_cfg_remove_key(cfgfile, section, "underrun_pct"); xmms_cfg_remove_key(cfgfile, section, "enable_crossfade"); xmms_cfg_remove_key(cfgfile, section, "enable_gapkiller"); xmms_cfg_remove_key(cfgfile, section, "mixer_use_master"); xmms_cfg_remove_key(cfgfile, section, "late_effect"); xmms_cfg_remove_key(cfgfile, section, "gap_lead_length"); /* config items used in v0.1 */ xmms_cfg_write_string (cfgfile, section, "output_plugin", config->op_name ? config->op_name : DEFAULT_OP_NAME); xmms_cfg_write_string (cfgfile, section, "op_config_string", config->op_config_string ? config->op_config_string : DEFAULT_OP_CONFIG_STRING); xmms_cfg_write_int (cfgfile, section, "buffer_size", config->mix_size_ms); xmms_cfg_write_int (cfgfile, section, "sync_size", config->sync_size_ms); xmms_cfg_write_int (cfgfile, section, "preload_size", config->preload_size_ms); xmms_cfg_write_int (cfgfile, section, "songchange_timeout", config->songchange_timeout); xmms_cfg_write_boolean(cfgfile, section, "enable_mixer", config->enable_mixer); xmms_cfg_write_boolean(cfgfile, section, "mixer_reverse", config->mixer_reverse); xmms_cfg_write_boolean(cfgfile, section, "enable_debug", config->enable_debug); xmms_cfg_write_boolean(cfgfile, section, "enable_monitor", config->enable_monitor); /* config items introduced by v0.2 */ xmms_cfg_write_boolean(cfgfile, section, "gap_lead_enable", config->gap_lead_enable); xmms_cfg_write_int (cfgfile, section, "gap_lead_len_ms", config->gap_lead_len_ms); xmms_cfg_write_int (cfgfile, section, "gap_lead_level", config->gap_lead_level); xmms_cfg_write_boolean(cfgfile, section, "gap_trail_enable", config->gap_trail_enable); xmms_cfg_write_int (cfgfile, section, "gap_trail_len_ms", config->gap_trail_len_ms); xmms_cfg_write_int (cfgfile, section, "gap_trail_level", config->gap_trail_level); xmms_cfg_write_int (cfgfile, section, "gap_trail_locked", config->gap_trail_locked); /* config items introduced by v0.2.1 */ xmms_cfg_write_boolean(cfgfile, section, "buffer_size_auto", config->mix_size_auto); /* config items introduced by v0.2.3 */ xmms_cfg_write_boolean(cfgfile, section, "album_detection", config->album_detection); /* config items introduced by v0.2.4 */ xmms_cfg_write_boolean(cfgfile, section, "http_workaround", config->enable_http_workaround); xmms_cfg_write_boolean(cfgfile, section, "enable_op_max_used", config->enable_op_max_used); xmms_cfg_write_int (cfgfile, section, "op_max_used_ms", config->op_max_used_ms); /* config items introduced by v0.3.0 */ #ifdef VOLUME_NORMALIZER xmms_cfg_write_boolean(cfgfile, section, "volnorm_enable", config->volnorm_enable); xmms_cfg_write_boolean(cfgfile, section, "volnorm_use_qa", config->volnorm_use_qa); xmms_cfg_write_int (cfgfile, section, "volnorm_target", config->volnorm_target); #endif xmms_cfg_write_boolean(cfgfile, section, "output_keep_opened", config->output_keep_opened); xmms_cfg_write_boolean(cfgfile, section, "mixer_software", config->mixer_software); xmms_cfg_write_int (cfgfile, section, "mixer_vol_left", config->mixer_vol_left); xmms_cfg_write_int (cfgfile, section, "mixer_vol_right", config->mixer_vol_right); /* config items introduced by v0.3.2 */ xmms_cfg_write_boolean(cfgfile, section, "no_xfade_if_same_file",config->no_xfade_if_same_file); /* config items introduced by v0.3.2 */ xmms_cfg_write_boolean(cfgfile, section, "gap_crossing", config->gap_crossing); /* fade configs */ write_fade_config(cfgfile, section, "fc_xfade", &config->fc[FADE_CONFIG_XFADE]); write_fade_config(cfgfile, section, "fc_manual", &config->fc[FADE_CONFIG_MANUAL]); write_fade_config(cfgfile, section, "fc_album", &config->fc[FADE_CONFIG_ALBUM]); write_fade_config(cfgfile, section, "fc_start", &config->fc[FADE_CONFIG_START]); write_fade_config(cfgfile, section, "fc_stop", &config->fc[FADE_CONFIG_STOP]); write_fade_config(cfgfile, section, "fc_eop", &config->fc[FADE_CONFIG_EOP]); write_fade_config(cfgfile, section, "fc_seek", &config->fc[FADE_CONFIG_SEEK]); write_fade_config(cfgfile, section, "fc_pause", &config->fc[FADE_CONFIG_PAUSE]); /* *INDENT-ON* */ xmms_cfg_write_default_file(cfgfile); xmms_cfg_free(cfgfile); DEBUG(("[crossfade] save_config: configuration saved\n")); } else DEBUG(("[crossfade] save_config: error saving configuration!\n")); } #define SAFE_FREE(x) if(x) { g_free(x); x = NULL; } void xfade_free_config() { SAFE_FREE(xfg->op_config_string); SAFE_FREE(xfg->op_name); g_list_foreach(config->presets, g_free_f, NULL); g_list_free(config->presets); config->presets = NULL; } void xfade_load_plugin_config(gchar *config_string, gchar *plugin_name, plugin_config_t *plugin_config) { update_plugin_config(&config_string, plugin_name, plugin_config, FALSE); } void xfade_save_plugin_config(gchar **config_string, gchar *plugin_name, plugin_config_t *plugin_config) { update_plugin_config(config_string, plugin_name, plugin_config, TRUE); } /*** helpers *****************************************************************/ gint xfade_cfg_out_skip(fade_config_t *fc) { if (!fc) return 0; switch (fc->config) { case FADE_CONFIG_TIMING: return fc->out_skip_ms; } return 0; } gint xfade_cfg_fadeout_len(fade_config_t *fc) { if (!fc) return 0; switch (fc->type) { case FADE_TYPE_SIMPLE_XF: return fc->simple_len_ms; case FADE_TYPE_ADVANCED_XF: return fc->out_enable ? fc->out_len_ms : 0; case FADE_TYPE_FADEOUT: case FADE_TYPE_PAUSE_ADV: return fc->out_len_ms; } return 0; } gint xfade_cfg_fadeout_volume(fade_config_t *fc) { gint volume; if (!fc) return 0; switch (fc->type) { case FADE_TYPE_ADVANCED_XF: case FADE_TYPE_FADEOUT: volume = fc->out_volume; if (volume < 0) volume = 0; if (volume > 100) volume = 100; return volume; } return 0; } gint xfade_cfg_offset(fade_config_t *fc) { if (!fc) return 0; switch (fc->type) { case FADE_TYPE_FLUSH: return fc->flush_pause_enable ? fc->flush_pause_len_ms : 0; case FADE_TYPE_PAUSE: return fc->pause_len_ms; case FADE_TYPE_SIMPLE_XF: return -fc->simple_len_ms; case FADE_TYPE_ADVANCED_XF: switch (fc->ofs_type) { case FC_OFFSET_LOCK_OUT: return -fc->out_len_ms; case FC_OFFSET_LOCK_IN: return -fc->in_len_ms; case FC_OFFSET_CUSTOM: return fc->ofs_custom_ms; } return 0; case FADE_TYPE_FADEOUT: case FADE_TYPE_PAUSE_ADV: return fc->ofs_custom_ms; } return 0; } gint xfade_cfg_in_skip(fade_config_t *fc) { if (!fc) return 0; switch (fc->config) { case FADE_CONFIG_TIMING: return fc->in_skip_ms; } return 0; } gint xfade_cfg_fadein_len(fade_config_t *fc) { if (!fc) return 0; switch (fc->type) { case FADE_TYPE_FLUSH: return fc->flush_in_enable ? fc->flush_in_len_ms : 0; case FADE_TYPE_SIMPLE_XF: return fc->simple_len_ms; case FADE_TYPE_ADVANCED_XF: return fc->in_locked ? (fc->out_enable ? fc->out_len_ms : 0) : (fc->in_enable ? fc->in_len_ms : 0); case FADE_TYPE_FADEIN: case FADE_TYPE_PAUSE_ADV: return fc->in_len_ms; } return 0; } gint xfade_cfg_fadein_volume(fade_config_t *fc) { gint volume; if (!fc) return 0; switch (fc->type) { case FADE_TYPE_FLUSH: volume = fc->flush_in_volume; break; case FADE_TYPE_ADVANCED_XF: volume = fc->in_locked ? fc->out_volume : fc->in_volume; break; case FADE_TYPE_FADEIN: volume = fc->in_volume; break; default: volume = 0; } if (volume < 0) volume = 0; if (volume > 100) volume = 100; return volume; } gboolean xfade_cfg_gap_trail_enable(config_t *cfg) { return xfg->gap_trail_locked ? xfg->gap_lead_enable : xfg->gap_trail_enable; } gint xfade_cfg_gap_trail_len(config_t *cfg) { if (!xfade_cfg_gap_trail_enable(cfg)) return 0; return xfg->gap_trail_locked ? xfg->gap_lead_len_ms : xfg->gap_trail_len_ms; } gint xfade_cfg_gap_trail_level(config_t *cfg) { return xfg->gap_trail_locked ? xfg->gap_lead_level : xfg->gap_trail_level; } gint xfade_mix_size_ms(config_t *cfg) { if (xfg->mix_size_auto) { gint i, min_size = 0; for (i = 0; i < MAX_FADE_CONFIGS; i++) { gint size = xfade_cfg_fadeout_len(&xfg->fc[i]); gint offset = xfade_cfg_offset(&xfg->fc[i]); if (xfg->fc[i].type == FADE_TYPE_PAUSE_ADV) size += xfade_cfg_fadein_len(&xfg->fc[i]); if (size < -offset) size = -offset; if (size > min_size) min_size = size; } return min_size += xfade_cfg_gap_trail_len(cfg) + xfg->songchange_timeout; } else return xfg->mix_size_ms; } /*****************************************************************************/