sound/synth/emux/emux_synth.c

Source file repositories/reference/linux-study-clean/sound/synth/emux/emux_synth.c

File Facts

System
Linux kernel
Corpus path
sound/synth/emux/emux_synth.c
Extension
.c
Size
24437 bytes
Lines
942
Domain
Driver Families
Bucket
sound/synth
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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 (emu->ops.prepare) {
			vp->state = SNDRV_EMUX_ST_OFF;
			if (emu->ops.prepare(vp) >= 0)
				vp->state = SNDRV_EMUX_ST_STANDBY;
		}
	}

	/* start envelope now */
	for (i = 0; i < emu->max_voices; i++) {
		vp = &emu->voices[i];
		if (vp->state == SNDRV_EMUX_ST_STANDBY &&
		    vp->chan == chan) {
			emu->ops.trigger(vp);
			vp->state = SNDRV_EMUX_ST_ON;
			vp->ontime = jiffies; /* remember the trigger timing */
		}
	}

#ifdef SNDRV_EMUX_USE_RAW_EFFECT
	if (port->port_mode == SNDRV_EMUX_PORT_MODE_OSS_SYNTH) {
		/* clear voice position for the next note on this channel */
		struct snd_emux_effect_table *fx = chan->private;
		if (fx) {
			fx->flag[EMUX_FX_SAMPLE_START] = 0;
			fx->flag[EMUX_FX_COARSE_SAMPLE_START] = 0;
		}
	}
#endif
}

/*
 * Release a note in response to a midi note off.
 */
void
snd_emux_note_off(void *p, int note, int vel, struct snd_midi_channel *chan)
{
	int ch;
	struct snd_emux *emu;
	struct snd_emux_voice *vp;
	struct snd_emux_port *port;

	port = p;
	if (snd_BUG_ON(!port || !chan))
		return;

	emu = port->emu;
	if (snd_BUG_ON(!emu || !emu->ops.release))
		return;

	guard(spinlock_irqsave)(&emu->voice_lock);
	for (ch = 0; ch < emu->max_voices; ch++) {
		vp = &emu->voices[ch];
		if (STATE_IS_PLAYING(vp->state) &&
		    vp->chan == chan && vp->key == note) {
			vp->state = SNDRV_EMUX_ST_RELEASED;
			if (vp->ontime == jiffies) {
				/* if note-off is sent too shortly after
				 * note-on, emuX engine cannot produce the sound
				 * correctly.  so we'll release this note
				 * a bit later via timer callback.
				 */
				vp->state = SNDRV_EMUX_ST_PENDING;
				if (! emu->timer_active) {
					mod_timer(&emu->tlist, jiffies + 1);
					emu->timer_active = 1;
				}
			} else
				/* ok now release the note */
				emu->ops.release(vp);
		}
	}
}

/*
 * timer callback
 *
 * release the pending note-offs
 */
void snd_emux_timer_callback(struct timer_list *t)
{
	struct snd_emux *emu = timer_container_of(emu, t, tlist);
	struct snd_emux_voice *vp;
	int ch, do_again = 0;

	guard(spinlock_irqsave)(&emu->voice_lock);
	for (ch = 0; ch < emu->max_voices; ch++) {
		vp = &emu->voices[ch];
		if (vp->state == SNDRV_EMUX_ST_PENDING) {
			if (vp->ontime == jiffies)
				do_again++; /* release this at the next interrupt */

Annotation

Implementation Notes