/***********************************************
 *  globals.c                                 
 *                                            
 *  Copyright 2001 Eric Kratzer.              
 *  Includes Xaudio software Copyright (C)
 *           1996-2000 Xaudio Corporation
 *           All Rights Reserved.               
 *
 *  This file is part of imp3sh.
 *                                            
 *  imp3sh is free software; you can distribute
 *  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.
 *
 *  imp3sh 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 recieved a copy of the GNU
 *  General Public License along with imp3sh; if
 *  not, write to the Free Software Foundation,
 *  Inc., 59 Temple Place, Suite 330, Boston MA
 *  02111-1307 USA
 ************************************************/

/************************************
 *          Include Files           *
 ************************************/

#include "imp3sh.h"

/************************************
 *          Global Variables        *
 ************************************/

char *PLAYMODES[] = { 
    "Once",
    "Repeat",
    "TrueRandom",
    "SmartRandom",
    "Learn",
    "Queued"
};
char *TIMESTAMP[] = { 
    "Off", 
    "On - Time played",
    "On - Time left"
};
char *AUDDRV[] = { 
    "Single process only",
    "Multiple processes allowed"
};
char *SEARCHPRF[] = { 
    "Tag, then Filename",
    "Tag, then Path/Filename",
    "Path/Filename",
    "Filename"
};
char *STATES[] = { 
    "Init", 
    "Idle", 
    "Play", 
    "Paused", 
    "External" 
};
char *OnOff[] = { 
    "Disabled", 
    "Enabled" 
};

char *c_path          = NULL;	/* current path              */
char *cmnd            = NULL;	/* comm buff                 */
char *current         = NULL;	/* current stream            */
char *last_stream     = NULL;	/* last stream played        */
char *current_info    = NULL;	/* current stream's info     */
char *host            = NULL;	/* hostname                  */
char *strinfo         = NULL;	/* current stream's info     */
char *last_expl       = NULL;	/* last explosion pos        */
char *xa_output       = NULL;	/* xaudio output stream      */

ListDef *active_list  = NULL;	/* current active list       */
ListDef *edit_list    = NULL;	/* current edit list         */
ListDef *history      = NULL;	/* history/Queue list        */

DCharBuf *chist_list  = NULL;	/* command history buffer    */
DCharBuf *aliases     = NULL;	/* user aliases              */
DCharBuf *args        = NULL;	/* user args                 */
DCharBuf *out_buffer  = NULL;   /* output ('Mess') buffer    */
DCharBuf *console_buf = NULL;   /* console output buffer     */
DCharBuf *decoder_log = NULL;   /* log buffer                */

XA_Control *player    = NULL;           /* internal decoder control  */
XA_PositionInfo pinfo = { 0, 0 };	/* current position          */
XA_VolumeInfo vinfo   = { 0, 0, 0 };	/* mixer info                */
XA_TimecodeInfo tinfo = { 0, 0, 0, 0 };	/* current stream's time     */
XA_TimecodeInfo dinfo = { 0, 0, 0, 0 };	/* current stream's duration */
XA_EqualizerInfo equalizer;	        /* Xaudio equalizer info     */

ProcessState state = IDLE;	/* current decoder state     */

/* terminal */
int thisprgp    = 0;	        /* this tty group            */
int tab_length  = 0;	        /* # spaces per '\t'         */
int tty_width   = 0;	        /* terminal width (chars)    */
int tty_height  = 0;	        /* terminal height (chars)   */
struct termios savtty, newtty;	/* tty settings              */

/* command */
int comm_len = 0;		/* user command length       */
int edit_pos = 0;		/* current edit pos          */

/* flags */
flag_t read_file_tags       = TRUE;
flag_t tried_gettag         = FALSE;
flag_t sort_mode            = TAG_FILE_PREF;

flag_t output_open          = FALSE;
flag_t decoder_open         = FALSE;
flag_t stream_open          = FALSE;
flag_t output_muted         = FALSE;
flag_t djmode_enabled       = FALSE;
flag_t external_player      = FALSE;
flag_t inside_queue         = FALSE;
flag_t user_stream          = FALSE;
flag_t external_paused      = FALSE;
flag_t ignore_stream_weight = FALSE;
flag_t multiple_audio_procs = FALSE;

flag_t prompt_now           = FALSE;
flag_t spackle              = FALSE;
flag_t key_press            = FALSE;
flag_t parenthesis          = FALSE;
flag_t ignore_hist_input    = FALSE;
flag_t ignore_char_input    = FALSE;

flag_t show_time_stamp      = FALSE;
flag_t auto_report          = FALSE;
flag_t auto_recover         = FALSE;
flag_t equalizer_enabled    = FALSE;

flag_t running_builtin      = FALSE;
flag_t piped_io_flag        = FALSE;
flag_t exit_flag            = FALSE;

/* terminal-dependant strings */
TermCtrl t_ctrl[] = {
    {"cl", NULL},		/* clear screen         */
    {"cd", NULL},		/* clear to bottom      */
    {"ce", NULL},		/* clear to end of line */
    {"nd", NULL},		/* non-destructive left */
    {"up", NULL},		/* cursor up one line   */
    {"cr", NULL},		/* carriage return      */

    {"ku", NULL},		/* up arrow             */
    {"kd", NULL},		/* down arrow           */
    {"kr", NULL},		/* right arrow          */
    {"kl", NULL},		/* left arrow           */
    {"kh", NULL},		/* home key             */
    {"@7", NULL},		/* end key              */
    {"kI", NULL},		/* insert key           */
    {"kD", NULL},		/* delete key           */
    {"kP", NULL},		/* page up key          */
    {"kN", NULL},		/* page down key        */

    /* Function keys */
    {"k1", NULL},		/* F1 */
    {"k2", NULL},
    {"k3", NULL},
    {"k4", NULL},
    {"k5", NULL},
    {"k6", NULL},
    {"k7", NULL},
    {"k8", NULL},
    {"k9", NULL},
    {"k;", NULL},
    {"F1", NULL},
    {"F2", NULL},		/* F12 */

    /* raw arrow key handling */
    {"up2", "\x1b[A"},
    {"down2", "\x1b[B"},
    {"right2", "\x1b[C"},
    {"left2", "\x1b[D"}
};

/* external player list */
PlayerDef player_list_s = { 
    "Built-in decoder", "n/a",
#ifdef OGG_MODULE
    ".MP3,.OGG",
#else
    ".MP3",
#endif
    OUTP_NONE, SIGNAL_NONE, (PlayerDef *) NULL
};

PlayerDef *player_list = &player_list_s;

/* child signal handler */
sighandler_t sigchild_handler = handle_child_sigs;

/* holder for waiting external player */
PlayerDef *delayed_external_player = NULL;

/* equalizer band mapping - map 32 bands to 10 */
EQBandDef eqbands[] = {
    /* band 0 */ {0, 0},
    /* band 1 */ {1, 1},
    /* band 2 */ {2, 2},
    /* band 3 */ {3, 3},
    /* band 4 */ {4, 4},
    /* band 5 */ {5, 5},
    /* band 6 */ {6, 7},
    /* band 7 */ {8, 11},
    /* band 8 */ {12, 19},
    /* band 9 */ {20, 31}
};

/* dj mode key definitions */
DJKeyDef djkeys[] = {
    /* F1/F2   */ {FALSE, 0, 0, NULL},
    /* F3/F4   */ {FALSE, 0, 0, NULL},
    /* F5/F6   */ {FALSE, 0, 0, NULL},
    /* F7/F8   */ {FALSE, 0, 0, NULL},
    /* F9/F10  */ {FALSE, 0, 0, NULL},
    /* F11/F12 */ {FALSE, 0, 0, NULL}
};

/* User function table */
CommandDef com[] = { 
{print_info, "printinfo",
 "Print program info----> printinfo"},

{print_gpl, "printgpl",
 "Print copyright-------> printgpl"},

{print_help, "help",
 "Print help------------> help [<grep_strings> | 'keys']"},

{exit_imp3sh, "exit",
 "Exit------------------> exit"},

{play_comm, "play",
 "Play------------------> play [<stream_name>]"},

{stop_file, "stop",
 "Stop------------------> stop"},

{pause_file, "pause",
 "Pause-----------------> pause"},

{resume_file, "resume",
 "Resume----------------> resume"},

{next_file, "next",
 "Play next entry-------> next"},

{previous_file, "last",
 "Play last entry-------> last"},

{seek_file, "seek",
 "Seek------------------> seek (<offset> <scale>) | [+/-]<percent>"},

{set_mixer, "volume",
 "Set volume/balance----> volume [+/-]<master_vol> [+/-]<pcm_vol> [+/-]<balance>"},

{mute_output, "mute",
 "Mute output-----------> mute"},

{unmute_output, "unmute",
 "Unmute output---------> unmute"},

{print_status, "status",
 "Print status----------> status"},

{add_list, "addlist",
 "Add list--------------> addlist <list_name>"},

{remove_list, "dellist",
 "Delete list-----------> dellist ('*' | <list_name>)"},

{reset_list, "resetlist",
 "Reset list------------> resetlist ('*' | <list_name>)"},

{rename_list, "renamelist",
 "Rename list-----------> renamelist <list_name> <new_name>"},

{use_list, "uselist",
 "Set active list-------> uselist <list_name>"},

{use_next_list, "nextlist",
 "Next active list------> nextlist"},

{edit_list_comm, "editlist",
 "Set edit list---------> editlist <list_name>"},

{print_list_comm, "printlist",
 "Print list------------> printlist ['-l'] [<grep_strings>]"},

{print_list_status, "liststatus",
 "Print list status-----> liststatus [<list_name>]"},

{add_to_list, "copylist",
 "Copy list entry(s)----> copylist <source_list> ('*' | <index_spec_list> | <grep_strings>)"},

{add_file_to_list, "addfile",
 "Add file/stream-------> addfile <stream_name1> <stream_name2> ..."},

{add_dir_comm, "addir",
 "Add directory---------> addir [<path_name>]"},

{add_dir_comm, "addiR",
 "Add dir (recursive)---> addiR [<path_name>]"},

{toggle_read_tags, "readtags",
 "Toggle read-file-tags-> readtags"},

{play_list_index, "playindex",
 "Play list index-------> playindex <index>"},

{move_list_index, "moveindex",
 "Move list index-------> moveindex <targ_index> <dest_index>"},

{delete_list_index_comm, "delindex",
 "Delete list index-----> delindex ('*' | <index_spec> | <grep_strings>)"},

{sort_list, "sortlist",
 "Sort list-------------> sortlist"},

{save_list_comm, "savelist",
 "Save list-------------> savelist <file_name>"},

{load_list_comm, "loadlist",
 "Load list-------------> loadlist <file_name>"},

{save_all_lists, "saveall",
 "Save all lists--------> saveall <file_name>"},

{load_all_lists, "loadall",
 "Load all lists--------> loadall <file_name>"},

{print_queue, "printq",
 "Print queue-----------> printq [<grep_strings>]"},

{queue_list_index, "addq",
 "Queue list index------> addq (<index_spec_list> | <grep_strings>)"},

{queue_files_comm, "fileq",
 "Queue files or dirs---> fileq <stream_name1> <stream_name2> ..."},

{clear_queue, "clearq",
 "Clear queue-----------> clearq"},

{resize_queue, "sizeq",
 "Change queue size-----> sizeq <maximum_size>"},

{set_play_mode, "once",
 "Set mode Once---------> once"},

{set_play_mode, "repeat",
 "Set mode Repeat-------> repeat"},

{set_play_mode, "random",
 "Set mode TrueRandom---> random"},

{set_play_mode, "srandom",
 "Set mode SmartRandom--> srandom"},

{set_play_mode, "learn",
 "Set mode Learn--------> learn"},

{set_learn_weights, "setlearn",
 "Set learning weights--> setlearn <play_weight> <skip_weight>"},

{set_search_mode, "viewTF",
 "Set listview 'TF'-----> viewTF"},

{set_search_mode, "viewTPF",
 "Set listview 'TPF'----> viewTPF"},

{set_search_mode, "viewPF",
 "Set listview 'PF'-----> viewPF"},

{set_search_mode, "viewF",
 "Set listview 'F'------> viewF"},

{toggle_auto_rprt, "report",
 "Toggle auto report----> report"},

{toggle_dj_mode, "djmode",
 "Toggle DJ mode--------> djmode"},

{set_stamp_mode, "stampOff",
 "Set timestamp 'Off'---> stampOff"},

{set_stamp_mode, "stampTP",
 "Set timestamp 'TP'----> stampTP"},

{set_stamp_mode, "stampTL",
 "Set timestamp 'TL'----> stampTL"},

{show_id3tag, "printtag",
 "Print file tag--------> printtag (<list_index> | <file_name>)"},

{add_tag, "addtag",
 "Add/modify tag info---> addtag (<list_index> | <file_name>) <options...>"},

{print_id3_styles, "printstyles",
 "Print id3 tag styles--> printstyles [<grep_strings>]"},

{print_players, "printplayers",
 "Print players---------> printplayers"},

{add_player, "addplayer",
 "Add player------------> addplayer ['-q' | '-b'] ['-k'] <name> <command> <filetypes>"},

{show_eq_bands, "eqprint",
 "Print equalizer bands-> eqprint"},

{set_eq_band_comm, "eqsetband",
 "Set equalizer band(s)-> eqsetband ('*' | <band_number_list>) <band_value_list>"},

{set_equalizer, "eqenable",
 "Enable equalizer------> eqenable"},

{disable_equalizer, "eqdisable",
 "Disable equalizer-----> eqdisable"},

{print_events, "printevents",
 "Print event list------> printevents"},

{add_event_comm, "addevent",
 "Add event-------------> addevent ['-q'] ['-p'] <type_options...> <command>"},

{remove_event_comm, "delevent",
 "Delete event----------> delevent ('*' | <event_id>)"},

{source_comm, "source",
 "Exec cmnds in file----> source <file_name>"},

{show_chist, "history",
 "Print command history-> history [<grep_strings>]"},

{add_alias, "alias",
 "Add alias-------------> alias [<alias_name> <command>]"},

{remove_alias, "unalias",
 "Remove alias----------> unalias <alias_name>"},

{print_jobs, "jobs",
 "Print jobs------------> jobs"},

{flush_job_buff, "fjob",
 "Flush job buffer------> fjob <job_number>"},

{send_job_2fg, "fg",
 "Send job foreground---> fg [<job_number>]"},

{send_job_2bg, "bg",
 "Send job background---> bg [<job_number>]"},

{show_environ, "env",
 "Print environment-----> env [<grep_strings>]"},

{set_environ, "setenv",
 "Set environment-------> setenv <name> <value>"},

{change_dir, "cd",
 "Change directory------> cd ['-' | <path_name>]"},

{toggle_multiple_audio_procs, "audioprocs",
 "Toggle driver mode----> audioprocs"},

{toggle_auto_recover, "recover",
 "Toggle auto recover---> recover"},

{open_decoder, "decstart",
 "Start xaudio decoder--> decstart"},

{set_internal_output, "setoutput",
 "Set xaudio output-----> setoutput <full_path_name>"},

{show_dlog, "printlog",
 "Print log-------------> printlog"},

{clear_dlog, "clearlog",
 "Clear log-------------> clearlog"},

{try_to_exec, "", ""}
};



/****Variable allocation functions****/

void deallocate_vars()
{
    clear_proclist();
    clear_events();
    clear_players();
    clear_all_lists();

    f_dbuf(history->dcb);
    free(history);

    f_dbuf(chist_list);
    f_dbuf(aliases);
    f_dbuf(args);
    f_dbuf(out_buffer);
    f_dbuf(console_buf);
    f_dbuf(decoder_log);

    free(c_path);
    free(cmnd);
    free(current);
    free(last_stream);
    free(current_info);
    free(host);
    free(strinfo);
    free(xa_output);
}

void allocate_vars()
{
    /* init default list and list pointers */
    a_list("default");
    active_list = edit_list = g_list("default");
    update_list_env();

    /* init history */
    history = malloc(sizeof(ListDef));
    history->playmode = QUEUE_MODE;
    history->listview = TAG_FILE_PREF;
    history->dcb = i_dbuf("queue", HIST_SIZE, DCHAR_SHIFT);

    /* Init buffers */
    chist_list = i_dbuf("Command list", CHIST_SIZ, DCHAR_SHIFT);
    aliases = i_dbuf("Aliases", 128, DCHAR_GROW);
    args = i_dbuf("User args", 128, DCHAR_GROW);
    out_buffer = i_dbuf("Mess buffer", LIST_SIZE, DCHAR_GROW);
    console_buf = i_dbuf("Console buffer", CONB_SIZE, DCHAR_SHIFT);
    decoder_log = i_dbuf("Log", DLOG_SIZE, DCHAR_SHIFT);

    /* alloc misc */
    c_path = malloc(PATH_MAX);
    cmnd = malloc(COMM_SIZE);
    current = malloc(COMM_SIZE);
    current_info = malloc(COMM_SIZE);
    last_stream = malloc(COMM_SIZE);
    host = malloc(INFO_SIZE);
    strinfo = malloc(INFO_SIZE);

    /* init misc */
    memset(c_path, ZCHAR, PATH_MAX);
    memset(cmnd, ZCHAR, COMM_SIZE);
    memset(current, ZCHAR, COMM_SIZE);
    memset(current_info, ZCHAR, COMM_SIZE);
    memset(last_stream, ZCHAR, COMM_SIZE);
    memset(host, ZCHAR, INFO_SIZE);
    memset(strinfo, ZCHAR, INFO_SIZE);
}

void /* user */ resize_queue()
{
    char *str;
    int new_size;

    str = g_dbuf(args, 1);

    if (!is_all_digits(str))
	print_cmnd_help(RESIZE_QUEUE);
    else {
	new_size = atoi(str);
	if (new_size > 0) {
	    if (!resize_dbuf(history->dcb, new_size))
		show_user(ERROR_MSG " Failed to resize queue");
	    else
		show_user(STATUS_MSG " Maximum queue size set to: %d",
			  history->dcb->size);
	} else
	    show_user(DEBUG_MSG " Invalid queue size: %d", new_size);
    }
}

/* misc option setting and reporting */

void set_state(ProcessState s)
{
    if (external_player && s == IDLE)
	state = EXTERNAL;
    else
	state = s;

    mysetenv(CURR_STATE, STATES[state]);
}

void clear_time()
{
    int i;

    for (i = 0; i < MAX_DJ_KEYS; i++)
	djkeys[i].set = FALSE;

    memset(&tinfo, 0, sizeof(XA_TimecodeInfo));
    memset(&pinfo, 0, sizeof(XA_PositionInfo));
}

void clear_duration()
{
    memset(&dinfo, 0, sizeof(XA_TimecodeInfo));
}

void clear_info()
{
    clear_time();
    tried_gettag = FALSE;

    if (*current != ZCHAR)
	safe_strcpy(last_stream, current, COMM_SIZE);

    memset(current, ZCHAR, COMM_SIZE);
    memset(current_info, ZCHAR, COMM_SIZE);
    memset(strinfo, ZCHAR, INFO_SIZE);

    mysetenv(CURR_INFO, NULL);
    mysetenv(CURR_STREAM, NULL);
}

void report_memuse()
{
    char fbuf[32];
    unsigned bytec;

    bytec = 0;

    bytec += g_jobs_bytec();
    bytec += g_playlist_bytec();
    bytec += g_player_bytec();
    bytec += g_event_bytec();

    bytec += g_dbuf_bytec(out_buffer);
    bytec += g_dbuf_bytec(console_buf);
    bytec += g_dbuf_bytec(decoder_log);
    bytec += g_dbuf_bytec(chist_list);
    bytec += g_dbuf_bytec(aliases);
    bytec += g_dbuf_bytec(args);
    bytec += g_dbuf_bytec(history->dcb);
    bytec += PATH_MAX + COMM_SIZE * 4 + INFO_SIZE * 2;

    if (bytec > (1024 * 1024)) {
	sprintf(fbuf, "%.2f", (((float) bytec) / 1024.0) / 1024.0);
	add_outbuffer("\tMemory    : %s MBytes malloc'ed", fbuf);
    } else {
	sprintf(fbuf, "%.2f", ((float) bytec) / 1024.0);
	add_outbuffer("\tMemory    : %s KBytes malloc'ed", fbuf);
    }
}

void report_name(char *stream)
{
    char *what;

    if (stream) {
	safe_strcpy(current, stream, COMM_SIZE);
	mysetenv(CURR_STREAM, current);

	if (auto_report) {
	    if (read_file_tags && !tried_gettag) {
		get_stream_info(current, current_info);
		tried_gettag = TRUE;
	    }

	    if (*current_info == ZCHAR)
		what = file_from_path(current);
	    else
		what = skip_space(current_info);

	    if ((key_press || !running_builtin) && have_tty()
		&& !piped_io_flag) outstr("\n");

	    show_user(REPORT_MSG " %s", what);
	}
    }
}

void /* user */ print_status()
{
    char tmp[INFO_SIZE], tmp2[8];
    float perc;
    int i;

    add_outbuffer(MISC_MSG " Stream");

    if (read_file_tags && !tried_gettag) {
	get_stream_info(current, current_info);
	tried_gettag = TRUE;
    }

    if (*current_info != ZCHAR)
	add_outbuffer("\tTag       : %s", skip_space(current_info));
    else
	add_outbuffer("\tName      : %s", file_from_path(current));

    add_outbuffer("\tInfo      : %s", strinfo);

    if (state == EXTERNAL) {
	sprintf(tmp, "%.2d:%.2d:%.2d", tinfo.h, tinfo.m, tinfo.s);
	add_outbuffer("\tPosition  : %s", tmp);
    } else if (stream_open) {
	if (pinfo.range)
	    perc = 100.0 * ((float) pinfo.offset / (float) pinfo.range);
	else
	    perc = 0.0;

	sprintf(tmp, "%.2d:%.2d:%.2d", dinfo.h, dinfo.m, dinfo.s);
	add_outbuffer("\tLength    : %s", tmp);
	sprintf(tmp, "%.2d:%.2d:%.2d (%d%%)",
		tinfo.h, tinfo.m, tinfo.s, (int) perc);
	add_outbuffer("\tPosition  : %s", tmp);
    }

    add_outbuffer(MISC_MSG " Player");
    add_outbuffer("\tState     : %s", STATES[state]);
    add_outbuffer("\tReport    : %s", OnOff[auto_report]);
    add_outbuffer("\tRecover   : %s", OnOff[auto_recover]);
    add_outbuffer("\tRead tags : %s", OnOff[read_file_tags]);
    report_memuse();

    add_outbuffer(MISC_MSG " Audio");
    if (state == EXTERNAL) {
	if (multiple_audio_procs && decoder_open)
	    strcpy(tmp, "Shared");
	else if (external_player)
	    strcpy(tmp, "External");
	else 
	    strcpy(tmp, "Free");
    } else if (decoder_open && output_open) {
	if (output_muted)
	    strcpy(tmp, "Muted");
	else if (xa_output)
	    strcpy(tmp, xa_output);
	else
	    strcpy(tmp, "Default");
    } else
	strcpy(tmp, "Free");

    add_outbuffer("\tOutput    : %s", tmp);

    if (state != EXTERNAL && decoder_open)
	strcpy(tmp, OnOff[djmode_enabled]);
    else
	strcpy(tmp, "Unavailable");

    add_outbuffer("\tDJ mode   : %s", tmp);

    if (state != EXTERNAL && decoder_open) {
	if (equalizer_enabled) {
	    *tmp = ZCHAR;
	    for (i = 0; i < MAX_EQ_BANDS; i++) {
		sprintf(tmp2, "%d", equalizer.left[eqbands[i].low]);
		strcat(tmp, tmp2);
		if (i != (MAX_EQ_BANDS - 1))
		    strcat(tmp, ".");
	    }
	} else
	    strcpy(tmp, "Disabled");
    } else
	strcpy(tmp, "Unavailable");

    add_outbuffer("\tEqualizer : %s", tmp);

    if (decoder_open && output_open && 
	(state != EXTERNAL || multiple_audio_procs)) {
	sprintf(tmp, "Master.%d Pcm.%d Balance.%d",
		vinfo.master_level, vinfo.pcm_level, vinfo.balance);
    } else
	strcpy(tmp, "Unavailable");

    add_outbuffer("\tMixer     : %s", tmp);

    flush_outbuffer();
}

void /* user */ toggle_multiple_audio_procs()
{
    multiple_audio_procs = !multiple_audio_procs;
    show_user(STATUS_MSG " Audio driver: %s", AUDDRV[multiple_audio_procs]);
}

void /* user */ toggle_auto_recover()
{
    auto_recover = !auto_recover;
    show_user(STATUS_MSG " Auto recover %s", OnOff[auto_recover]);
}

void /* user */ toggle_auto_rprt()
{
    auto_report = !auto_report;
    show_user(STATUS_MSG " Auto report %s", OnOff[auto_report]);
}

void /* user */ toggle_read_tags()
{
    read_file_tags = !read_file_tags;
    show_user(STATUS_MSG " Read-file-tags %s", OnOff[read_file_tags]);
}

void /* user */ set_stamp_mode()
{
    char *comm; 

    comm = g_dbuf(args, 0);

    if (strcmp(comm, com[SET_STAMP_OFF].name) == 0)
	show_time_stamp = TIME_OFF;
    else if (strcmp(comm, com[SET_STAMP_TIMP].name) == 0)
	show_time_stamp = TIME_NORM;
    else if (strcmp(comm, com[SET_STAMP_TIML].name) == 0)
	show_time_stamp = TIME_LEFT;

    show_user(STATUS_MSG " Timestamp %s", TIMESTAMP[show_time_stamp]);
}

void /* user */ set_play_mode()
{
    char *comm;
    
    comm = g_dbuf(args, 0);

    if (!edit_list)
	show_user(DEBUG_MSG " Edit list undefined");
    else {
	if (strcmp(comm, com[SET_MODE_ONCE].name) == 0)
	    edit_list->playmode = ONCE_MODE;
	else if (strcmp(comm, com[SET_MODE_REPEAT].name) == 0)
	    edit_list->playmode = REPEAT_MODE;
	else if (strcmp(comm, com[SET_MODE_TRANDOM].name) == 0)
	    edit_list->playmode = TRANDOM_MODE;
	else if (strcmp(comm, com[SET_MODE_SRANDOM].name) == 0)
	    edit_list->playmode = SRANDOM_MODE;
	else if (strcmp(comm, com[SET_MODE_LEARN].name) == 0)
	    edit_list->playmode = LEARN_MODE;

	show_user(STATUS_MSG " \"%s\" list mode set to %s",
		  edit_list->dcb->name, PLAYMODES[edit_list->playmode]);
    }
}

void /* user */ set_search_mode()
{
    char *comm;

    comm = g_dbuf(args, 0);

    if (!edit_list)
	show_user(DEBUG_MSG " Edit list undefined");
    else {
	if (strcmp(comm, com[SET_PREF_TF].name) == 0)
	    edit_list->listview = TAG_FILE_PREF;
	else if (strcmp(comm, com[SET_PREF_TPF].name) == 0)
	    edit_list->listview = TAG_PATH_PREF;
	else if (strcmp(comm, com[SET_PREF_PF].name) == 0)
	    edit_list->listview = PATH_FILE_PREF;
	else if (strcmp(comm, com[SET_PREF_F].name) == 0)
	    edit_list->listview = FILE_ONLY_PREF;

	show_user(STATUS_MSG " \"%s\" list view set to: %s",
		  edit_list->dcb->name, SEARCHPRF[edit_list->listview]);
    }
}

void /* user */ set_learn_weights()
{
    char *pw, *sw;
    int ipw, isw;

    pw = g_dbuf(args, 1);
    sw = g_dbuf(args, 2);

    if (!pw || !sw)
	print_cmnd_help(SET_LEARN_WEIGHTS);
    else if (!edit_list)
	show_user(DEBUG_MSG " Edit list undefined");
    else {
	ipw = atoi(pw);
	isw = atoi(sw);
	if (ipw <= 0 || ipw > 127)
	    show_user(DEBUG_MSG
		      " Invalid weight: \"%s\", valid range is [1, 127]", pw);
	else if (isw <= 0 || isw > 127)
	    show_user(DEBUG_MSG
		      " Invalid weight: \"%s\", valid range is [1, 127]", sw);
	else {
	    edit_list->play_weight = ipw;
	    edit_list->skip_weight = isw;
	}
    }
}
