sound/drivers/opl4/opl4_synth.c

Source file repositories/reference/linux-study-clean/sound/drivers/opl4/opl4_synth.c

File Facts

System
Linux kernel
Corpus path
sound/drivers/opl4/opl4_synth.c
Extension
.c
Size
22897 bytes
Lines
621
Domain
Driver Families
Bucket
sound/drivers
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

if (voice->chan == chan && voice->note == note) {
			func(opl4, voice);
		}
	}
}

/*
 * Executes the callback for all voices of to the specified channel.
 */
static void snd_opl4_do_for_channel(struct snd_opl4 *opl4,
				    struct snd_midi_channel *chan,
				    void (*func)(struct snd_opl4 *opl4, struct opl4_voice *voice))
{
	int i;
	struct opl4_voice *voice;

	guard(spinlock_irqsave)(&opl4->reg_lock);
	for (i = 0; i < OPL4_MAX_VOICES; i++) {
		voice = &opl4->voices[i];
		if (voice->chan == chan) {
			func(opl4, voice);
		}
	}
}

/*
 * Executes the callback for all active voices.
 */
static void snd_opl4_do_for_all(struct snd_opl4 *opl4,
				void (*func)(struct snd_opl4 *opl4, struct opl4_voice *voice))
{
	int i;
	struct opl4_voice *voice;

	guard(spinlock_irqsave)(&opl4->reg_lock);
	for (i = 0; i < OPL4_MAX_VOICES; i++) {
		voice = &opl4->voices[i];
		if (voice->chan)
			func(opl4, voice);
	}
}

static void snd_opl4_update_volume(struct snd_opl4 *opl4, struct opl4_voice *voice)
{
	int att;

	att = voice->sound->tone_attenuate;
	att += snd_opl4_volume_table[opl4->chset->gs_master_volume & 0x7f];
	att += snd_opl4_volume_table[voice->chan->gm_volume & 0x7f];
	att += snd_opl4_volume_table[voice->chan->gm_expression & 0x7f];
	att += snd_opl4_volume_table[voice->velocity];
	att = 0x7f - (0x7f - att) * (voice->sound->volume_factor) / 0xfe - volume_boost;
	if (att < 0)
		att = 0;
	else if (att > 0x7e)
		att = 0x7e;
	snd_opl4_write(opl4, OPL4_REG_LEVEL + voice->number,
		       (att << 1) | voice->level_direct);
	voice->level_direct = 0;
}

static void snd_opl4_update_pan(struct snd_opl4 *opl4, struct opl4_voice *voice)
{
	int pan = voice->sound->panpot;

	if (!voice->chan->drum_channel)
		pan += (voice->chan->control[MIDI_CTL_MSB_PAN] - 0x40) >> 3;
	if (pan < -7)
		pan = -7;
	else if (pan > 7)
		pan = 7;
	voice->reg_misc = (voice->reg_misc & ~OPL4_PAN_POT_MASK)
		| (pan & OPL4_PAN_POT_MASK);
	snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc);
}

static void snd_opl4_update_vibrato_depth(struct snd_opl4 *opl4,
					  struct opl4_voice *voice)
{
	int depth;

	if (voice->chan->drum_channel)
		return;
	depth = (7 - voice->sound->vibrato)
		* (voice->chan->control[MIDI_CTL_VIBRATO_DEPTH] & 0x7f);
	depth = (depth >> 7) + voice->sound->vibrato;
	voice->reg_lfo_vibrato &= ~OPL4_VIBRATO_DEPTH_MASK;
	voice->reg_lfo_vibrato |= depth & OPL4_VIBRATO_DEPTH_MASK;
	snd_opl4_write(opl4, OPL4_REG_LFO_VIBRATO + voice->number,
		       voice->reg_lfo_vibrato);

Annotation

Implementation Notes