[alsa-devel] [PATCH] make sbiload to use hwdep interface
This patch makes sbiload using the hwdep interface instead of seq instr layer. This simplifies the logic a lot.
Takashi
diff -r 9b306261208b seq/sbiload/README --- a/seq/sbiload/README Mon Oct 22 15:16:35 2007 +0200 +++ b/seq/sbiload/README Fri Oct 26 16:10:50 2007 +0200 @@ -1,4 +1,4 @@ This is sbiload - an OPL2/3 FM instrumen -This is sbiload - an OPL2/3 FM instrument loader for ALSA sequencer +This is sbiload - an OPL2/3 FM instrument loader for ALSA hwdep
Written by Uros Bizjak uros@kss-loka.si Web: http://www.kss-loka.si/~uros/sbiload.html @@ -14,62 +14,42 @@ By default it will install into /usr/loc By default it will install into /usr/local/bin, change INSTDIR in make.conf to change this.
-Before use ----------- - -Please check that the correct sequencer modules are loaded for your -sound card. You need to load snd-synth-opl3 module. - Usage -----
- loadsbi [-p client:port] [-4] [-l] [-P path] [-v level] instfile drumfile + loadsbi [-D device] [-4] [-P path] [-v level] instfile drumfile
- -p, --port=client:port - An ALSA client and port number to use + -D, --device=name - An ALSA hwdep name to use -4 --opl3 - Four operators (OPL3) file type - -l, --list - List possible output ports -P, --path=path - Specify the patch path -v, --verbose=level - Verbose level
-Because you may have more than one sound card and each sound -card may have several MIDI connections, you have to tell sbiload -which one to use. +When you have multiple sound cards and/or there may be multiple OPL2/3 +synth devices, you have to tell sbiload which one to use, and pass its +hwdep name via -D option. Otherwise, sbiload will load the data onto +the first found device.
-First find out what the possibilities are for your system: +To find out the hwdep name of the OPL devices, check +/proc/asound/hwdep file first. It has the list of hwdep devices +currently available on your system.
-If you run: - - sbiload -l + % cat /proc/asound/hwdep + 00-00: Emux WaveTable + 00-01: OPL3 FM + 01-00: OPL3 FM
-it will give you a list of the devices. On my system I get: - - Port Client name Port name - 64:0 0: MIDI Synth MIDI 0-0 - 65:0 OPL3 FM Synth OPL3 FM Synth port +In the example above, you have two OPL3 devices. To the first one +(00-01), which means the first card (00-) and the second device (01), +pass "-D hw:0,1". For the second OPL3 device (01-00), pass "-D +hw:1,0" instead.
- -Only OPLx FM Synth port can be used with sbiload. In the example above -the first one is the external Midi port, and the second is the internal -four-operator FM synthesizer (OPL3). - -If you don't see anything listed then check that the correct ALSA -modules are loaded as in the section "Before use".
Running sbiload ---------------
-You specify the port to use with the -p option, or by setting the -environment variable ALSA_OUT_PORT. +Pass the instrument and drum file data as arguments.
-For example to use port 0 on client 65 to load four-operator FM -instrument - - sbiload -p 65:0 --opl3 std.o3 drums.o3 - -or - - export ALSA_OUT_PORT=65:0 - sbiload --opl3 std.o3 drums.o3 + % sbiload std.o3 drums.o3
Acknowledgements diff -r 9b306261208b seq/sbiload/sbiload.c --- a/seq/sbiload/sbiload.c Mon Oct 22 15:16:35 2007 +0200 +++ b/seq/sbiload/sbiload.c Fri Oct 26 16:10:50 2007 +0200 @@ -1,5 +1,5 @@ /* - * ALSA sequencer SBI FM instrument loader + * ALSA hwdep SBI FM instrument loader * Copyright (c) 2000 Uros Bizjak uros@kss-loka.si * * This program is free software; you can redistribute it and/or modify @@ -16,11 +16,13 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * + * + * Oct. 2007 - Takashi Iwai tiwai@suse.de + * Changed to use hwdep instead of obsoleted seq-instr interface */
#include <errno.h> #include <getopt.h> -#include <alsa/sound/ainstr_fm.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -29,24 +31,12 @@ #include <fcntl.h> #include <errno.h> #include <alsa/asoundlib.h> +#include <alsa/sound/asound_fm.h> #include <sys/time.h> #include <unistd.h>
-typedef struct sbi_header -{ - char key[4]; - char name[32]; -} -sbi_header_t; - -typedef struct sbi_inst -{ - sbi_header_t header; #define DATA_LEN_2OP 16 #define DATA_LEN_4OP 24 - char data[DATA_LEN_4OP]; -} -sbi_inst_t;
/* offsets for SBI params */ #define AM_VIB 0 @@ -59,21 +49,20 @@ sbi_inst_t; #define CONNECTION 10 #define OFFSET_4OP 11
-/* offsets in sbi_header.name for SBI extensions */ -#define ECHO_DELAY 25 -#define ECHO_ATTEN 26 -#define CHORUS_SPREAD 27 -#define TRNSPS 28 -#define FIX_DUR 29 -#define MODES 30 -#define FIX_KEY 31 +/* offsets for SBI extensions */ +#define ECHO_DELAY 0 +#define ECHO_ATTEN 1 +#define CHORUS_SPREAD 2 +#define TRNSPS 3 +#define FIX_DUR 4 +#define MODES 5 +#define FIX_KEY 6
/* Options for the command */ #define HAS_ARG 1 static struct option long_opts[] = { - {"port", HAS_ARG, NULL, 'p'}, + {"device", HAS_ARG, NULL, 'D'}, {"opl3", 0, NULL, '4'}, - {"list", 0, NULL, 'l'}, {"path", HAS_ARG, NULL, 'P'}, {"verbose", HAS_ARG, NULL, 'v'}, {"version", 0, NULL, 'V'}, @@ -83,87 +72,35 @@ static struct option long_opts[] = { /* Number of elements in an array */ #define NELEM(a) ( sizeof(a)/sizeof((a)[0]) )
-#define ADDR_PARTS 4 /* Number of part in a port description addr 1:2:3:4 */ -#define SEP ", \t" /* Separators for port description */ - -#define SBI_FILE_TYPE_2OP 0 -#define SBI_FILE_TYPE_4OP 1 +enum { + FM_PATCH_UNKNOWN, + FM_PATCH_OPL2, + FM_PATCH_OPL3 +};
/* Default file type */ -int file_type = SBI_FILE_TYPE_2OP; +static int file_type = FM_PATCH_OPL2;
/* Default verbose level */ -int verbose = 0; +static int verbose = 0;
/* Global declarations */ -snd_seq_t *seq_handle; - -int seq_client; -int seq_port; -int seq_dest_client; -int seq_dest_port; +static snd_hwdep_t *handle;
#ifndef PATCHDIR #define PATCHDIR "/usr/share/sounds/opl3" #endif
-char *patchdir = PATCHDIR; +static char *patchdir = PATCHDIR;
/* Function prototypes */ -static void show_list (); -static void show_usage (); -static void show_op (fm_instrument_t * fm_instr); +static void show_usage (void); +static void show_op (struct sbi_patch * instr, int type);
-static int load_patch (fm_instrument_t * fm_instr, int bank, int prg, char *name); +static int load_patch (struct sbi_patch * instr); static int load_file (int bank, char *filename); -static int parse_portdesc (char *portdesc);
-static int init_client (); - -static void -ignore_errors (const char *file, int line, const char *function, int err, const char *fmt, ...) -{ - /* ignore */ -} - -/* - * Show a list of possible output ports that midi could be sent to. - */ -static void -show_list () { - snd_seq_client_info_t *cinfo; - snd_seq_port_info_t *pinfo; - - int client, err; - - snd_lib_error_set_handler (ignore_errors); - if ((err = snd_seq_open (&seq_handle, "hw", SND_SEQ_OPEN_DUPLEX, 0)) < 0) { - fprintf (stderr, "Could not open sequencer: %s\n", snd_strerror (err)); - return; - } - - printf (" Port %-30.30s %s\n", "Client name", "Port name"); - snd_seq_client_info_alloca(&cinfo); - snd_seq_client_info_set_client(cinfo, -1); - while (snd_seq_query_next_client(seq_handle, cinfo) >= 0) { - client = snd_seq_client_info_get_client(cinfo); - snd_seq_port_info_alloca(&pinfo); - snd_seq_port_info_set_client(pinfo, client); - snd_seq_port_info_set_port(pinfo, -1); - while (snd_seq_query_next_port(seq_handle, pinfo) >= 0) { - unsigned int cap; - - cap = (SND_SEQ_PORT_CAP_SUBS_WRITE | SND_SEQ_PORT_CAP_WRITE); - if ((snd_seq_port_info_get_capability(pinfo) & cap) == cap) { - printf ("%3d:%-3d %-30.30s %s\n", - client, snd_seq_port_info_get_port(pinfo), - snd_seq_client_info_get_name(cinfo), - snd_seq_port_info_get_name(pinfo)); - } - } - } - snd_seq_close (seq_handle); -} +static int init_hwdep (const char *name);
/* * Show usage message @@ -172,11 +109,10 @@ show_usage () { show_usage () { char **cpp; static char *msg[] = { - "Usage: sbiload [-p client:port] [-4] [-l] [-P path] [-v level] instfile drumfile", + "Usage: sbiload [-D device] [-4] [-P path] [-v level] instfile drumfile", "", - " -p client:port - A alsa client and port number to send midi to", + " -D device - hwdep device string", " -4 - four operators file type (default = two ops)", - " -l - List possible output ports that could be used", " -P path - Specify the patch path", " -v level - Verbose level (default = 0)", " -V - Show version", @@ -199,169 +135,86 @@ show_version () { * Show instrument FM operators */ static void -show_op (fm_instrument_t * fm_instr) { +show_op (struct sbi_patch * inst, int type) { int i = 0; + int ofs = 0;
do { - printf (" OP%i: flags: %s %s %s %s\011OP%i: flags: %s %s %s %s\n", - i, - fm_instr->op[i].am_vib & (1 << 7) ? "AM" : " ", - fm_instr->op[i].am_vib & (1 << 6) ? "VIB" : " ", - fm_instr->op[i].am_vib & (1 << 5) ? "EGT" : " ", - fm_instr->op[i].am_vib & (1 << 4) ? "KSR" : " ", - i + 1, - fm_instr->op[i + 1].am_vib & (1 << 7) ? "AM" : " ", - fm_instr->op[i + 1].am_vib & (1 << 6) ? "VIB" : " ", - fm_instr->op[i + 1].am_vib & (1 << 5) ? "EGT" : " ", - fm_instr->op[i + 1].am_vib & (1 << 4) ? "KSR" : ""); - printf (" OP%i: MULT = 0x%x" "\011\011OP%i: MULT = 0x%x\n", - i, fm_instr->op[i].am_vib & 0x0f, - i + 1, fm_instr->op[i + 1].am_vib & 0x0f); - printf (" OP%i: KSL = 0x%x TL = 0x%.2x\011OP%i: KSL = 0x%x TL = 0x%.2x\n", - i, (fm_instr->op[i].ksl_level >> 6) & 0x03, fm_instr->op[i].ksl_level & 0x3f, - i + 1, (fm_instr->op[i + 1].ksl_level >> 6) & 0x03, fm_instr->op[i + 1].ksl_level & 0x3f); - printf (" OP%i: AR = 0x%x DL = 0x%x\011OP%i: AR = 0x%x DL = 0x%x\n", - i, (fm_instr->op[i].attack_decay >> 4) & 0x0f, fm_instr->op[i].attack_decay & 0x0f, - i + 1, (fm_instr->op[i + 1].attack_decay >> 4) & 0x0f, fm_instr->op[i + 1].attack_decay & 0x0f); - printf (" OP%i: SL = 0x%x RR = 0x%x\011OP%i: SL = 0x%x RR = 0x%x\n", - i, (fm_instr->op[i].sustain_release >> 4) & 0x0f, fm_instr->op[i].sustain_release & 0x0f, - i + 1, (fm_instr->op[i + 1].sustain_release >> 4) & 0x0f, fm_instr->op[i + 1].sustain_release & 0x0f); - printf (" OP%i: WS = 0x%x\011\011OP%i: WS = 0x%x\n", - i, fm_instr->op[i].wave_select & 0x07, - i + 1, fm_instr->op[i + 1].wave_select & 0x07); - printf (" FB = 0x%x, %s\n", - (fm_instr->feedback_connection[i / 2] >> 1) & 0x07, - fm_instr->feedback_connection[i / 2] & (1 << 0) ? "parallel" : "serial"); - i += 2; + unsigned char val; + val = inst->data[AM_VIB + ofs]; + printf (" OP%i: flags: %s %s %s %s", i, + val & (1 << 7) ? "AM" : " ", + val & (1 << 6) ? "VIB" : " ", + val & (1 << 5) ? "EGT" : " ", + val & (1 << 4) ? "KSR" : " "); + val = inst->data[AM_VIB + ofs + 1]; + printf ("\011OP%i: flags: %s %s %s %s\n", i + 1, + val & (1 << 7) ? "AM" : " ", + val & (1 << 6) ? "VIB" : " ", + val & (1 << 5) ? "EGT" : " ", + val & (1 << 4) ? "KSR" : " "); + val = inst->data[AM_VIB + ofs]; + printf (" OP%i: MULT = 0x%x", i, val & 0x0f); + val = inst->data[AM_VIB + ofs + 1]; + printf ("\011\011OP%i: MULT = 0x%x\n", i + 1, val & 0x0f); + + val = inst->data[KSL_LEVEL + ofs]; + printf (" OP%i: KSL = 0x%x TL = 0x%.2x", i, + (val >> 6) & 0x03, val & 0x3f); + val = inst->data[KSL_LEVEL + ofs + 1]; + printf ("\011OP%i: KSL = 0x%x TL = 0x%.2x\n", i + 1, + (val >> 6) & 0x03, val & 0x3f); + val = inst->data[ATTACK_DECAY + ofs]; + printf (" OP%i: AR = 0x%x DL = 0x%x", i, + (val >> 4) & 0x0f, val & 0x0f); + val = inst->data[ATTACK_DECAY + ofs + 1]; + printf ("\011OP%i: AR = 0x%x DL = 0x%x\n", i + 1, + (val >> 4) & 0x0f, val & 0x0f); + val = inst->data[SUSTAIN_RELEASE + ofs]; + printf (" OP%i: SL = 0x%x RR = 0x%x", i, + (val >> 4) & 0x0f, val & 0x0f); + val = inst->data[SUSTAIN_RELEASE + ofs + 1]; + printf ("\011OP%i: SL = 0x%x RR = 0x%x\n", i + 1, + (val >> 4) & 0x0f, val & 0x0f); + val = inst->data[WAVE_SELECT + ofs]; + printf (" OP%i: WS = 0x%x", i, val & 0x07); + val = inst->data[WAVE_SELECT + ofs + 1]; + printf ("\011\011OP%i: WS = 0x%x\n", i + 1, val & 0x07); + val = inst->data[CONNECTION + ofs]; + printf (" FB = 0x%x, %s\n", (val >> 1) & 0x07, + val & (1 << 0) ? "parallel" : "serial"); + i += 2; + ofs += OFFSET_4OP; } - while (i == (fm_instr->type == FM_PATCH_OPL3) << 1); + while (i == (type == FM_PATCH_OPL3) << 1);
printf (" Extended data:\n" " ED = %.3i EA = %.3i CS = %.3i TR = %.3i\n" " FD = %.3i MO = %.3i FK = %.3i\n", - fm_instr->echo_delay, fm_instr->echo_atten, fm_instr->chorus_spread, fm_instr->trnsps, - fm_instr->fix_dur, fm_instr->modes, fm_instr->fix_key); -} - -/* - * Check the result of the previous instr event - */ -static int -check_result (int evtype) { - snd_seq_event_t *pev; - int err; - - for (;;) { - if ((err = snd_seq_event_input (seq_handle, &pev)) < 0) { - fprintf (stderr, "Unable to read event input: %s\n", - snd_strerror (err)); - return -ENXIO; - } - if (pev->type == SND_SEQ_EVENT_RESULT && pev->data.result.event == evtype) - break; - snd_seq_free_event (pev); - } - err = pev->data.result.result; - snd_seq_free_event (pev); - - return err; + inst->extension[ECHO_DELAY], inst->extension[ECHO_ATTEN], + inst->extension[CHORUS_SPREAD], inst->extension[TRNSPS], + inst->extension[FIX_DUR], inst->extension[MODES], + inst->extension[FIX_KEY]); }
/* * Send patch to destination port */ static int -load_patch (fm_instrument_t * fm_instr, int bank, int prg, char *name) { - snd_instr_header_t *put; - snd_seq_instr_t id; - snd_seq_event_t ev; +load_patch (struct sbi_patch * inst) {
- size_t size; - int err; - - if (verbose > 1) { - printf ("%.3i: [OPL%i] %s\n", prg, fm_instr->type == FM_PATCH_OPL3 ? 3 : 2, name); - show_op (fm_instr); - } - - if ((err = snd_instr_fm_convert_to_stream (fm_instr, name, &put, &size)) < 0) { - fprintf (stderr, "Unable to convert instrument %.3i to stream: %s\n", - prg, snd_strerror (err)); - return -1; - } - memset(&id, 0, sizeof(id)); - id.std = SND_SEQ_INSTR_TYPE2_OPL2_3; - id.prg = prg; - id.bank = bank; - snd_instr_header_set_id(put, &id); - - /* build event */ - memset (&ev, 0, sizeof (ev)); - ev.source.client = seq_client; - ev.source.port = seq_port; - ev.dest.client = seq_dest_client; - ev.dest.port = seq_dest_port; - - ev.flags = SND_SEQ_EVENT_LENGTH_VARUSR; - ev.queue = SND_SEQ_QUEUE_DIRECT; - -__again: - ev.type = SND_SEQ_EVENT_INSTR_PUT; - ev.data.ext.len = size; - ev.data.ext.ptr = put; - - if ((err = snd_seq_event_output (seq_handle, &ev)) < 0) { + ssize_t ret; + ret = snd_hwdep_write(handle, inst, sizeof(*inst)); + if (ret != sizeof(*inst)) { fprintf (stderr, "Unable to write an instrument %.3i put event: %s\n", - prg, snd_strerror (err)); + inst->prog, snd_strerror (ret)); return -1; }
- if ((err = snd_seq_drain_output (seq_handle)) < 0) { - fprintf (stderr, "Unable to write instrument %.3i data: %s\n", prg, - snd_strerror (err)); - return -1; - } - - err = check_result (SND_SEQ_EVENT_INSTR_PUT); - if (err >= 0) { - if (verbose) - printf ("Loaded instrument %.3i, bank %.3i: %s\n", prg, bank, name); - return 0; - } else if (err == -EBUSY) { - snd_instr_header_t *remove; - - snd_instr_header_alloca(&remove); - snd_instr_header_set_cmd(remove, SND_SEQ_INSTR_FREE_CMD_SINGLE); - snd_instr_header_set_id(remove, snd_instr_header_get_id(put)); - - /* remove instrument */ - ev.type = SND_SEQ_EVENT_INSTR_FREE; - ev.data.ext.len = snd_instr_header_sizeof(); - ev.data.ext.ptr = remove; - - if ((err = snd_seq_event_output (seq_handle, &ev)) < 0) { - fprintf (stderr, "Unable to write an instrument %.3i free event: %s\n", - prg, snd_strerror (err)); - return -1; - } - - if ((err = snd_seq_drain_output (seq_handle)) < 0) { - fprintf (stderr, "Unable to write instrument %.3i data: %s\n", prg, - snd_strerror (err)); - return -1; - } - - if ((err = check_result (SND_SEQ_EVENT_INSTR_FREE)) < 0) { - fprintf (stderr, "Instrument %.3i, bank %.3i - free error: %s\n", - prg, bank, snd_strerror (err)); - return -1; - } - goto __again; - } - - fprintf (stderr, "Instrument %.3i, bank %.3i - put error: %s\n", - prg, bank, snd_strerror (err)); - return -1; + if (verbose) + printf ("Loaded instrument %.3i, bank %.3i: %s\n", + inst->prog, inst->bank, inst->name); + return 0; }
/* @@ -369,66 +222,45 @@ __again: */ static void load_sb (int bank, int fd) { - int len, i; + int len; int prg; - - sbi_inst_t sbi_instr; - fm_instrument_t fm_instr; + struct sbi_patch inst; int fm_instr_type;
- len = (file_type == SBI_FILE_TYPE_4OP) ? DATA_LEN_4OP : DATA_LEN_2OP; + len = (file_type == FM_PATCH_OPL2) ? DATA_LEN_4OP : DATA_LEN_2OP; for (prg = 0;; prg++) { - if (read (fd, &sbi_instr.header, sizeof (sbi_header_t)) < (ssize_t)sizeof (sbi_header_t)) + inst.prog = prg; + inst.bank = bank; + + if (read (fd, inst.key, 4) != 4) break;
- if (!strncmp (sbi_instr.header.key, "SBI\032", 4) || !strncmp (sbi_instr.header.key, "2OP\032", 4)) { + if (!memcmp (inst.key, "SBI\032", 4) || !memcmp (inst.key, "2OP\032", 4)) { + len = DATA_LEN_2OP; fm_instr_type = FM_PATCH_OPL2; - } else if (!strncmp (sbi_instr.header.key, "4OP\032", 4)) { + } else if (!strncmp (inst.key, "4OP\032", 4)) { + len = DATA_LEN_4OP; fm_instr_type = FM_PATCH_OPL3; } else { - fm_instr_type = 0; if (verbose) printf ("%.3i: wrong instrument key!\n", prg); + fm_instr_type = FM_PATCH_UNKNOWN; }
- if (read (fd, &sbi_instr.data, len) < len) + if (read (fd, &inst.name, sizeof(inst.name)) != sizeof(inst.name) || + read (fd, &inst.extension, sizeof(inst.extension)) != sizeof(inst.extension) || + read (fd, &inst.data, len) != len) break;
- if (fm_instr_type == 0) + if (fm_instr_type == FM_PATCH_UNKNOWN) continue;
- memset (&fm_instr, 0, sizeof (fm_instr)); - fm_instr.type = fm_instr_type; - - for (i = 0; i < 2; i++) { - fm_instr.op[i].am_vib = sbi_instr.data[AM_VIB + i]; - fm_instr.op[i].ksl_level = sbi_instr.data[KSL_LEVEL + i]; - fm_instr.op[i].attack_decay = sbi_instr.data[ATTACK_DECAY + i]; - fm_instr.op[i].sustain_release = sbi_instr.data[SUSTAIN_RELEASE + i]; - fm_instr.op[i].wave_select = sbi_instr.data[WAVE_SELECT + i]; - } - fm_instr.feedback_connection[0] = sbi_instr.data[CONNECTION]; - - if (fm_instr_type == FM_PATCH_OPL3) { - for (i = 0; i < 2; i++) { - fm_instr.op[i + 2].am_vib = sbi_instr.data[OFFSET_4OP + AM_VIB + i]; - fm_instr.op[i + 2].ksl_level = sbi_instr.data[OFFSET_4OP + KSL_LEVEL + i]; - fm_instr.op[i + 2].attack_decay = sbi_instr.data[OFFSET_4OP + ATTACK_DECAY + i]; - fm_instr.op[i + 2].sustain_release = sbi_instr.data[OFFSET_4OP + SUSTAIN_RELEASE + i]; - fm_instr.op[i + 2].wave_select = sbi_instr.data[OFFSET_4OP + WAVE_SELECT + i]; - } - fm_instr.feedback_connection[1] = sbi_instr.data[OFFSET_4OP + CONNECTION]; + if (verbose > 1) { + printf ("%.3i: %s\n", inst.prog, inst.name); + show_op (&inst, fm_instr_type); }
- fm_instr.echo_delay = sbi_instr.header.name[ECHO_DELAY]; - fm_instr.echo_atten = sbi_instr.header.name[ECHO_ATTEN]; - fm_instr.chorus_spread = sbi_instr.header.name[CHORUS_SPREAD]; - fm_instr.trnsps = sbi_instr.header.name[TRNSPS]; - fm_instr.fix_dur = sbi_instr.header.name[FIX_DUR]; - fm_instr.modes = sbi_instr.header.name[MODES]; - fm_instr.fix_key = sbi_instr.header.name[FIX_KEY]; - - if (load_patch (&fm_instr, bank, prg, sbi_instr.header.name) < 0) + if (load_patch (&inst) < 0) break; } return; @@ -461,92 +293,57 @@ load_file (int bank, char *filename) { }
/* - * Parse port description + * Open a hwdep device */ -static int -parse_portdesc (char *portdesc) { - char *astr; - char *cp; - int a[ADDR_PARTS]; - int count; +static int open_hwdep (const char *name) +{ + int err; + snd_hwdep_info_t *info;
- if (portdesc == NULL) - return -1; + if ((err = snd_hwdep_open (&handle, name, SND_HWDEP_OPEN_WRITE)) < 0) + return err;
- for (astr = strtok (portdesc, SEP); astr; astr = strtok (NULL, SEP)) { - for (cp = astr, count = 0; cp && *cp; cp++) { - if (count < ADDR_PARTS) - a[count++] = atoi (cp); - cp = strchr (cp, ':'); - if (cp == NULL) - break; - } - - if (count == 2) { - seq_dest_client = a[0]; - seq_dest_port = a[1]; - } else { - printf ("Addresses in %d parts not supported yet\n", count); - return -1; - } + snd_hwdep_info_alloca(&info); + if (!snd_hwdep_info (handle, info)) { + snd_hwdep_iface_t iface = snd_hwdep_info_get_iface(info); + if (iface == SND_HWDEP_IFACE_OPL2 || iface == SND_HWDEP_IFACE_OPL3) + return 0; } - return 0; + snd_hwdep_close(handle); + handle = NULL; + return -EINVAL; }
-/* - * Open sequencer, create client port and - * subscribe client to destination port - */ static int -init_client () { - char name[64]; - snd_seq_port_subscribe_t *sub; - snd_seq_addr_t addr; +init_hwdep (const char *name) { + int err; + char tmpname[16];
- if ((err = snd_seq_open (&seq_handle, "hw", SND_SEQ_OPEN_DUPLEX, 0)) < 0) { - fprintf (stderr, "Could not open sequencer: %s\n", snd_strerror (err)); + if (!name || !*name) { + /* auto probe */ + int card = -1; + snd_ctl_t *ctl; + + while (!snd_card_next(&card) && card >= 0) { + int dev; + sprintf(tmpname, "hw:%d", card); + if (snd_ctl_open(&ctl, tmpname, 0) < 0) + continue; + dev = -1; + while (!snd_ctl_hwdep_next_device(ctl, &dev) && dev >= 0) { + sprintf(tmpname, "hw:%d,%d", card, dev); + if (!open_hwdep(tmpname)) + return 0; + } + snd_ctl_close(ctl); + } + fprintf (stderr, "Can't find any OPL3 hwdep device\n"); return -1; }
- seq_client = snd_seq_client_id (seq_handle); - if (seq_client < 0) { - snd_seq_close (seq_handle); - fprintf (stderr, "Unable to determine my client number: %s\n", - snd_strerror (err)); - return -1; - } - - sprintf (name, "sbiload - %i", getpid ()); - if ((err = snd_seq_set_client_name (seq_handle, name)) < 0) { - snd_seq_close (seq_handle); - fprintf (stderr, "Unable to set client info: %s\n", - snd_strerror (err)); - return -1; - } - - if ((seq_port = snd_seq_create_simple_port (seq_handle, "Output", - SND_SEQ_PORT_CAP_READ | SND_SEQ_PORT_CAP_WRITE, - SND_SEQ_PORT_TYPE_SPECIFIC)) < 0) { - snd_seq_close (seq_handle); - fprintf (stderr, "Unable to create a client port: %s\n", - snd_strerror (seq_port)); - return -1; - } - - snd_seq_port_subscribe_alloca(&sub); - addr.client = seq_client; - addr.port = seq_port; - snd_seq_port_subscribe_set_sender(sub, &addr); - addr.client = seq_dest_client; - addr.port = seq_dest_port; - snd_seq_port_subscribe_set_dest(sub, &addr); - snd_seq_port_subscribe_set_exclusive(sub, 1); - - if ((err = snd_seq_subscribe_port (seq_handle, sub)) < 0) { - snd_seq_close (seq_handle); - fprintf (stderr, "Unable to subscribe destination port: %s\n", - snd_strerror (errno)); + if ((err = open_hwdep (name)) < 0) { + fprintf (stderr, "Could not open hwdep %s: %s\n", name, snd_strerror (err)); return -1; }
@@ -558,40 +355,25 @@ init_client () { * and close sequencer */ static void -finish_client () +finish_hwdep () { - snd_seq_port_subscribe_t *sub; - snd_seq_addr_t addr; - int err; - - snd_seq_port_subscribe_alloca(&sub); - addr.client = seq_client; - addr.port = seq_port; - snd_seq_port_subscribe_set_sender(sub, &addr); - addr.client = seq_dest_client; - addr.port = seq_dest_port; - snd_seq_port_subscribe_set_dest(sub, &addr); - if ((err = snd_seq_unsubscribe_port (seq_handle, sub)) < 0) { - fprintf (stderr, "Unable to unsubscribe destination port: %s\n", - snd_strerror (errno)); - } - snd_seq_close (seq_handle); + snd_hwdep_close(handle); + handle = NULL; }
/* * Load a .SBI FM instrument patch * sbiload [-p client:port] [-l] [-P path] [-v level] instfile drumfile * - * -p, --port=client:port - An ALSA client and port number to use + * -D, --device=name - An ALSA hwdep name to use * -4 --opl3 - four operators file type - * -l, --list - List possible output ports that could be used * -P, --path=path - Specify the patch path * -v, --verbose=level - Verbose level */ int main (int argc, char **argv) { char opts[NELEM (long_opts) * 2 + 1]; - char *portdesc; + char *name; char *cp; int c; struct option *op; @@ -604,7 +386,7 @@ main (int argc, char **argv) { *cp++ = ':'; }
- portdesc = NULL; + name = NULL;
/* Deal with the options */ for (;;) { @@ -613,11 +395,11 @@ main (int argc, char **argv) { break;
switch (c) { - case 'p': - portdesc = optarg; + case 'D': + name = optarg; break; case '4': - file_type = SBI_FILE_TYPE_4OP; + file_type = FM_PATCH_OPL3; break; case 'v': verbose = atoi (optarg); @@ -625,9 +407,6 @@ main (int argc, char **argv) { case 'V': show_version(); exit (1); - case 'l': - show_list (); - exit (0); case 'P': patchdir = optarg; break; @@ -637,30 +416,14 @@ main (int argc, char **argv) { } }
- if (portdesc == NULL) { - portdesc = getenv ("ALSA_OUT_PORT"); - if (portdesc == NULL) { - fprintf (stderr, "No client/port specified.\n" - "You must supply one with the -p option or with the\n" - "environment variable ALSA_OUT_PORT\n"); - exit (1); - } - } - - /* Parse port description to dest_client and dest_port */ - if (parse_portdesc (portdesc) < 0) { - return 1; - } - - /* Initialize client and subscribe to destination port */ - if (init_client () < 0) { + if (init_hwdep (name) < 0) { return 1; }
/* Process instrument and drum file */ if (optind < argc) { if (load_file (0, argv[optind++]) < 0) { - finish_client(); + finish_hwdep(); return 1; } } else { @@ -668,15 +431,14 @@ main (int argc, char **argv) { } if (optind < argc) { if (load_file (128, argv[optind]) < 0) { - finish_client(); + finish_hwdep(); return 1; } } else { fprintf(stderr, "Warning: drum file was not specified\n"); }
- /* Unsubscribe destination port and close client */ - finish_client(); + finish_hwdep();
return 0; }
participants (1)
-
Takashi Iwai