From: Yair K <ce...@gm...> - 2006-09-02 12:30:36
|
Hi, The patch below allows timidity to specify libao plugin options. This le= ts = the libao backend have similiar functionality to other backends (like = specifying different output devices - 'timidity -Od -o /dev/dsp2' and = 'TIMIDITY_LIBAO_OPTS=3D"dsp=3D/dev/dsp2" timidity -OO -o oss' will both = try to = use /dev/dsp2). It should also provide an ability not yet available in = timidity - using remote hosts for nas or esd output. A doc on libao options is at: http://www.xiph.org/ao/doc/drivers.html , = = but it is best to check the libao sources as the doc has a few errors an= d = omissions. Yours, Yair K. --- timidity/ao_a.c 2004-04-12 20:44:03.000000000 +0300 +++ timidity/ao_a.c 2006-09-02 13:57:03.699576000 +0300 @@ -38,6 +38,8 @@ #include "playmidi.h" #include "miditrace.h" +static void safe_ao_append_option(ao_option **options, const char *key,= = const char *value); +static void ao_set_options(int driver_id, ao_option **options); static int open_output(void); /* 0=3Dsuccess, 1=3Dwarning, -1=3Dfatal = error */ static void close_output(void); static int output_data(char *buf, int32 nbytes); @@ -62,6 +64,87 @@ static ao_device *ao_device_ctx; static ao_sample_format ao_sample_format_ctx; +static void safe_ao_append_option(ao_option **options, const char *key,= = const char *value) +{ + if (ao_append_option(options, key, value) =3D=3D 1) return; + else { + ctl->cmsg(CMSG_FATAL, VERB_NORMAL, + "Fatal error: ao_append_option has failed to allocate = memory"); + #ifdef ABORT_AT_FATAL + abort(); + #endif /* ABORT_AT_FATAL */ + safe_exit(10); + /*NOTREACHED*/ + } +} + +/* ao_set_options - set options for libao's plugins. + * First, it translates a few of TiMidity's defaults into libao's. + * Second, it allows the user to pass options via $TIMIDITY_LIBAO_OPTS.= + * + * TIMIDITY_LIBAO_OPTS should have "key=3Dvalue" pairs, multiple pairs = are + * seperated by commas. e.g. "use_mmap=3D1,dev=3Ddefault". Three import= ant = notes: + * 1. Spaces are not clipped, so "dsp =3D /dev/dsp2" will be passed as + * "dsp " (key) and " /dev/dsp" (value), which is not valid. + * 2. If nothing is present after the "=3D" in the pair, a NULL is + * used as the value. "host=3D,buf_size=3D8192" will be passed as "host= " =3D = "NULL" + * and "buf_size" =3D "8192". + * 3. Later options have precedence over previous ones in libao. + * "dsp=3D/dev/dsp2,dsp=3D/dev/dsp" will check only for /dev/dsp in the= oss = plugin. + */ +static void ao_set_options(int driver_id, ao_option **options) +{ + #define SUBDELIM '=3D' + const char delim =3D ','; + + char *opt_string =3D getenv ("TIMIDITY_LIBAO_OPTS"); + char *token, *value; + + char *driver_name =3D NULL; + + /* We can't rely on dpm.name, because the interface might have been + * selected by ao_default_driver (when dpm.name =3D=3D NULL) + */ + driver_name=3Dao_driver_info(driver_id)->short_name; + + /* We check for each plugin, since some parameters can have a differe= nt + * correct values in different plugins (e.g. "sun"'s dev vs. "alsa09"= 's = dev). + * and/or different ways of setting them in timidity. + */ + if (!strcmp(driver_name, "alsa09")) { + const char *env_pcm_name =3D getenv ("TIMIDITY_PCM_NAME"); + if (env_pcm_name !=3D NULL) safe_ao_append_option(options, "dev",= = env_pcm_name); + } else if (!strcmp(driver_name, "alsa")) { + const char *env_pcm_name =3D getenv ("TIMIDITY_PCM_NAME"); + const char *env_sound_card =3D getenv ("TIMIDITY_SOUND_CARD"); + if (env_sound_card !=3D NULL) safe_ao_append_option(options, "card"= , = env_sound_card); + if (env_pcm_name !=3D NULL) safe_ao_append_option(options, "dev", = env_pcm_name); + } + #ifdef OSS_DEVICE + else if (!strcmp(driver_name, "oss")) { + safe_ao_append_option(options, "dsp", OSS_DEVICE); + } + #endif + + if (opt_string =3D=3D NULL) return; + + token=3Dstrtok(opt_string, &delim); + while (token !=3D NULL) + { + value=3Dstrchr(token, SUBDELIM); + if ((value =3D=3D NULL) || (value =3D=3D token)) goto next; + *value=3D'\0'; + safe_ao_append_option(options, token, value+1); + /* value+1 is always defined since the string is NULL-terminated an= d + * strchr returns either NULL or a pointer before the NULL in the = string. + */ + + next: + token=3Dstrtok(NULL, &delim); + } + #undef SUBDELIM +} + void show_ao_device_info(FILE *fp) { int driver_count; @@ -92,6 +175,7 @@ static int open_output(void) { int driver_id; + ao_option *options =3D NULL; ao_initialize(); @@ -131,11 +215,15 @@ if (ao_sample_format_ctx.bits =3D=3D 0) ao_sample_format_ctx.bits =3D 8; - if ((ao_device_ctx =3D ao_open_live(driver_id, &ao_sample_format_ctx,= = NULL /* no options */)) =3D=3D NULL) { + ao_set_options(driver_id, &options); + + if ((ao_device_ctx =3D ao_open_live(driver_id, &ao_sample_format_ctx,= = options)) =3D=3D NULL) { ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s", dpm.name, strerror(errno)); + ao_free_options(options); return -1; } + ao_free_options(options); return 0; } -- = Using Opera's revolutionary e-mail client: http://www.opera.com/mail/ |