Skip to content

Commit

Permalink
[ALSA] opl3 - Use hwdep for patch loading
Browse files Browse the repository at this point in the history
Use the hwdep device for loading OPL2/3 patch data instead of the
messy sequencer instrument layer.
Due to this change, the sbiload program should be updated, too.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
  • Loading branch information
Takashi Iwai authored and Jaroslav Kysela committed Jan 31, 2008
1 parent ceac4bf commit 224a033
Show file tree
Hide file tree
Showing 7 changed files with 289 additions and 156 deletions.
19 changes: 19 additions & 0 deletions include/sound/asound_fm.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ struct snd_dm_fm_params {
#define SNDRV_DM_FM_IOCTL_SET_MODE _IOW('H', 0x25, int)
/* for OPL3 only */
#define SNDRV_DM_FM_IOCTL_SET_CONNECTION _IOW('H', 0x26, int)
/* SBI patch management */
#define SNDRV_DM_FM_IOCTL_CLEAR_PATCHES _IO ('H', 0x40)

#define SNDRV_DM_FM_OSS_IOCTL_RESET 0x20
#define SNDRV_DM_FM_OSS_IOCTL_PLAY_NOTE 0x21
Expand All @@ -112,4 +114,21 @@ struct snd_dm_fm_params {
#define SNDRV_DM_FM_OSS_IOCTL_SET_MODE 0x24
#define SNDRV_DM_FM_OSS_IOCTL_SET_OPL 0x25

/*
* Patch Record - fixed size for write
*/

#define FM_KEY_SBI "SBI\032"
#define FM_KEY_2OP "2OP\032"
#define FM_KEY_4OP "4OP\032"

struct sbi_patch {
unsigned char prog;
unsigned char bank;
char key[4];
char name[25];
char extension[7];
unsigned char data[32];
};

#endif /* __SOUND_ASOUND_FM_H */
58 changes: 55 additions & 3 deletions include/sound/opl3.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
#include "seq_oss_legacy.h"
#endif
#include "seq_device.h"
#include "ainstr_fm.h"
#include "asound_fm.h"

/*
* Register numbers for the global registers
Expand Down Expand Up @@ -239,6 +239,47 @@

struct snd_opl3;

/*
* Instrument record, aka "Patch"
*/

/* FM operator */
struct fm_operator {
unsigned char am_vib;
unsigned char ksl_level;
unsigned char attack_decay;
unsigned char sustain_release;
unsigned char wave_select;
} __attribute__((packed));

/* Instrument data */
struct fm_instrument {
struct fm_operator op[4];
unsigned char feedback_connection[2];
unsigned char echo_delay;
unsigned char echo_atten;
unsigned char chorus_spread;
unsigned char trnsps;
unsigned char fix_dur;
unsigned char modes;
unsigned char fix_key;
};

/* type */
#define FM_PATCH_OPL2 0x01 /* OPL2 2 operators FM instrument */
#define FM_PATCH_OPL3 0x02 /* OPL3 4 operators FM instrument */

/* Instrument record */
struct fm_patch {
unsigned char prog;
unsigned char bank;
unsigned char type;
struct fm_instrument inst;
char name[24];
struct fm_patch *next;
};


/*
* A structure to keep track of each hardware voice
*/
Expand Down Expand Up @@ -297,8 +338,8 @@ struct snd_opl3 {
struct snd_midi_channel_set * oss_chset;
#endif

struct snd_seq_kinstr_ops fm_ops;
struct snd_seq_kinstr_list *ilist;
#define OPL3_PATCH_HASH_SIZE 32
struct fm_patch *patch_table[OPL3_PATCH_HASH_SIZE];

struct snd_opl3_voice voices[MAX_OPL3_VOICES]; /* Voices (OPL3 'channel') */
int use_time; /* allocation counter */
Expand Down Expand Up @@ -333,8 +374,19 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3, int device, int seq_device,
int snd_opl3_open(struct snd_hwdep * hw, struct file *file);
int snd_opl3_ioctl(struct snd_hwdep * hw, struct file *file,
unsigned int cmd, unsigned long arg);
long snd_opl3_write(struct snd_hwdep *hw, const char __user *buf, long count,
loff_t *offset);
int snd_opl3_release(struct snd_hwdep * hw, struct file *file);

void snd_opl3_reset(struct snd_opl3 * opl3);

int snd_opl3_load_patch(struct snd_opl3 *opl3,
int prog, int bank, int type,
const char *name,
const unsigned char *ext,
const unsigned char *data);
struct fm_patch *snd_opl3_find_patch(struct snd_opl3 *opl3, int prog, int bank,
int create_patch);
void snd_opl3_clear_patches(struct snd_opl3 *opl3);

#endif /* __SOUND_OPL3_H */
2 changes: 2 additions & 0 deletions sound/drivers/opl3/opl3_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ static int snd_opl3_free(struct snd_opl3 *opl3)
snd_assert(opl3 != NULL, return -ENXIO);
if (opl3->private_free)
opl3->private_free(opl3);
snd_opl3_clear_patches(opl3);
release_and_free_resource(opl3->res_l_port);
release_and_free_resource(opl3->res_r_port);
kfree(opl3);
Expand Down Expand Up @@ -521,6 +522,7 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3,
/* operators - only ioctl */
hw->ops.open = snd_opl3_open;
hw->ops.ioctl = snd_opl3_ioctl;
hw->ops.write = snd_opl3_write;
hw->ops.release = snd_opl3_release;

opl3->seq_dev_num = seq_device;
Expand Down
41 changes: 17 additions & 24 deletions sound/drivers/opl3/opl3_midi.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,8 +289,6 @@ static int snd_opl3_oss_map[MAX_OPL3_VOICES] = {
void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
{
struct snd_opl3 *opl3;
struct snd_seq_instr wanted;
struct snd_seq_kinstr *kinstr;
int instr_4op;

int voice;
Expand All @@ -306,11 +304,13 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
unsigned char voice_offset;
unsigned short opl3_reg;
unsigned char reg_val;
unsigned char prg, bank;

int key = note;
unsigned char fnum, blocknum;
int i;

struct fm_patch *patch;
struct fm_instrument *fm;
unsigned long flags;

Expand All @@ -320,28 +320,26 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
snd_printk("Note on, ch %i, inst %i, note %i, vel %i\n",
chan->number, chan->midi_program, note, vel);
#endif
wanted.cluster = 0;
wanted.std = SNDRV_SEQ_INSTR_TYPE2_OPL2_3;

/* in SYNTH mode, application takes care of voices */
/* in SEQ mode, drum voice numbers are notes on drum channel */
if (opl3->synth_mode == SNDRV_OPL3_MODE_SEQ) {
if (chan->drum_channel) {
/* percussion instruments are located in bank 128 */
wanted.bank = 128;
wanted.prg = note;
bank = 128;
prg = note;
} else {
wanted.bank = chan->gm_bank_select;
wanted.prg = chan->midi_program;
bank = chan->gm_bank_select;
prg = chan->midi_program;
}
} else {
/* Prepare for OSS mode */
if (chan->number >= MAX_OPL3_VOICES)
return;

/* OSS instruments are located in bank 127 */
wanted.bank = 127;
wanted.prg = chan->midi_program;
bank = 127;
prg = chan->midi_program;
}

spin_lock_irqsave(&opl3->voice_lock, flags);
Expand All @@ -353,15 +351,14 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
}

__extra_prg:
kinstr = snd_seq_instr_find(opl3->ilist, &wanted, 1, 0);
if (kinstr == NULL) {
patch = snd_opl3_find_patch(opl3, prg, bank, 0);
if (!patch) {
spin_unlock_irqrestore(&opl3->voice_lock, flags);
return;
}

fm = KINSTR_DATA(kinstr);

switch (fm->type) {
fm = &patch->inst;
switch (patch->type) {
case FM_PATCH_OPL2:
instr_4op = 0;
break;
Expand All @@ -371,14 +368,12 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
break;
}
default:
snd_seq_instr_free_use(opl3->ilist, kinstr);
spin_unlock_irqrestore(&opl3->voice_lock, flags);
return;
}

#ifdef DEBUG_MIDI
snd_printk(" --> OPL%i instrument: %s\n",
instr_4op ? 3 : 2, kinstr->name);
instr_4op ? 3 : 2, patch->name);
#endif
/* in SYNTH mode, application takes care of voices */
/* in SEQ mode, allocate voice on free OPL3 channel */
Expand Down Expand Up @@ -569,8 +564,6 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
/* get extra pgm, but avoid possible loops */
extra_prg = (extra_prg) ? 0 : fm->modes;

snd_seq_instr_free_use(opl3->ilist, kinstr);

/* do the bookkeeping */
vp->time = opl3->use_time++;
vp->note = key;
Expand Down Expand Up @@ -601,12 +594,12 @@ void snd_opl3_note_on(void *p, int note, int vel, struct snd_midi_channel *chan)
/* allocate extra program if specified in patch library */
if (extra_prg) {
if (extra_prg > 128) {
wanted.bank = 128;
bank = 128;
/* percussions start at 35 */
wanted.prg = extra_prg - 128 + 35 - 1;
prg = extra_prg - 128 + 35 - 1;
} else {
wanted.bank = 0;
wanted.prg = extra_prg - 1;
bank = 0;
prg = extra_prg - 1;
}
#ifdef DEBUG_MIDI
snd_printk(" *** allocating extra program\n");
Expand Down
Loading

0 comments on commit 224a033

Please sign in to comment.