At Mon, 29 Oct 2007 08:41:40 +0100, Clemens Ladisch wrote:
Rene Herman wrote:
However -- there is a problem after all. [...] While much less annoying... something's still missing.
Several instruments aren't played at all, at least those with program number 40 and up (strings) and 64 and up (saxophones).
OK, how about the revised patch below to alsa-tools?
thanks,
Takashi
diff -r 9b306261208b seq/sbiload/README --- a/seq/sbiload/README Mon Oct 22 15:16:35 2007 +0200 +++ b/seq/sbiload/README Mon Oct 29 12:01:07 2007 +0100 @@ -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 Mon Oct 29 12:01:07 2007 +0100 @@ -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_OPL3) ? 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)) { fm_instr_type = FM_PATCH_OPL2; - } else if (!strncmp (sbi_instr.header.key, "4OP\032", 4)) { + } else if (!strncmp (inst.key, "4OP\032", 4)) { 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] %s\n", inst.prog, + fm_instr_type == FM_PATCH_OPL2 ? "OPL2" : "OPL3", + 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; }