Alsa-Devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback
@ 2024-04-01 10:07 Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 01/18] ALSA: emux: fix /proc teardown at module unload Oswald Buddenhagen
                   ` (18 more replies)
  0 siblings, 19 replies; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 10:07 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Jaroslav Kysela, Arthur Marsh

this fixes the regression i introduced (though arguably, i just made it broken
in a different way), and then some more.

Oswald Buddenhagen (18):
  ALSA: emux: fix /proc teardown at module unload
  ALSA: emux: prune unused parameter from snd_soundfont_load_guspatch()
  ALSA: emux: fix validation of snd_emux.num_ports
  ALSA: emux: fix init of patch_info.truesize in load_data()
  ALSA: emu10k1: prune vestiges of
    SNDRV_SFNT_SAMPLE_{BIDIR,REVERSE}_LOOP support
  ALSA: emux: centralize & improve patch info validation
  ALSA: emux: improve patch ioctl data validation
  ALSA: emu10k1: move patch loader assertions into low-level functions
  ALSA: emu10k1: fix sample signedness issues in wavetable loader
  ALSA: emu10k1: fix playback of 8-bit wavetable samples
  ALSA: emu10k1: make wavetable sample playback start position exact
  ALSA: emu10k1: shrink blank space in front of wavetable samples
  ALSA: emu10k1: merge conditions in patch loader
  ALSA: emu10k1: fix wavetable offset recalculation
  ALSA: emu10k1: de-duplicate size calculations for 16-bit samples
  ALSA: emu10k1: improve cache behavior documentation
  ALSA: emu10k1: fix playback of short wavetable samples
  ALSA: emux: simplify snd_sf_list.callback handling

 include/sound/emu10k1.h              |  32 +++--
 include/sound/soundfont.h            |   2 +-
 sound/isa/sb/emu8000_patch.c         |  13 --
 sound/pci/emu10k1/emu10k1_callback.c |  10 +-
 sound/pci/emu10k1/emu10k1_patch.c    | 207 +++++++++++----------------
 sound/pci/emu10k1/memory.c           |  55 +++++--
 sound/synth/emux/emux.c              |   6 +-
 sound/synth/emux/emux_hwdep.c        |   3 +-
 sound/synth/emux/emux_oss.c          |   3 +-
 sound/synth/emux/emux_proc.c         |   1 +
 sound/synth/emux/emux_seq.c          |   6 +-
 sound/synth/emux/soundfont.c         |  73 +++++++---
 12 files changed, 216 insertions(+), 195 deletions(-)

--
2.42.0.419.g70bf8a5751


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [PATCH 01/18] ALSA: emux: fix /proc teardown at module unload
  2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
@ 2024-04-01 10:07 ` Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 02/18] ALSA: emux: prune unused parameter from snd_soundfont_load_guspatch() Oswald Buddenhagen
                   ` (17 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 10:07 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Jaroslav Kysela, Arthur Marsh

We forgot to remember the wavetable /proc entry, so we'd fail to free it
at module unload.

This matters only when only the synth module is unloaded, as unloading
the card driver would tear down the sub-entry anyway.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 sound/synth/emux/emux_proc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sound/synth/emux/emux_proc.c b/sound/synth/emux/emux_proc.c
index 7993e6a01e54..820351f52551 100644
--- a/sound/synth/emux/emux_proc.c
+++ b/sound/synth/emux/emux_proc.c
@@ -102,6 +102,7 @@ void snd_emux_proc_init(struct snd_emux *emu, struct snd_card *card, int device)
 	entry->content = SNDRV_INFO_CONTENT_TEXT;
 	entry->private_data = emu;
 	entry->c.text.read = snd_emux_proc_info_read;
+	emu->proc = entry;
 }

 void snd_emux_proc_free(struct snd_emux *emu)
--
2.42.0.419.g70bf8a5751


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 02/18] ALSA: emux: prune unused parameter from snd_soundfont_load_guspatch()
  2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 01/18] ALSA: emux: fix /proc teardown at module unload Oswald Buddenhagen
@ 2024-04-01 10:07 ` Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 03/18] ALSA: emux: fix validation of snd_emux.num_ports Oswald Buddenhagen
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 10:07 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Jaroslav Kysela, Arthur Marsh

The `client` parameter was not used, so eliminate it from the call
chain.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 include/sound/soundfont.h     | 2 +-
 sound/synth/emux/emux_hwdep.c | 3 +--
 sound/synth/emux/emux_oss.c   | 3 +--
 sound/synth/emux/soundfont.c  | 7 +++----
 4 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/include/sound/soundfont.h b/include/sound/soundfont.h
index e445688a4f4f..98ed98d89d6d 100644
--- a/include/sound/soundfont.h
+++ b/include/sound/soundfont.h
@@ -89,7 +89,7 @@ struct snd_sf_list {
 int snd_soundfont_load(struct snd_sf_list *sflist, const void __user *data,
 		       long count, int client);
 int snd_soundfont_load_guspatch(struct snd_sf_list *sflist, const char __user *data,
-				long count, int client);
+				long count);
 int snd_soundfont_close_check(struct snd_sf_list *sflist, int client);

 struct snd_sf_list *snd_sf_new(struct snd_sf_callback *callback,
diff --git a/sound/synth/emux/emux_hwdep.c b/sound/synth/emux/emux_hwdep.c
index 81719bfb8ed7..fd8f978cde1c 100644
--- a/sound/synth/emux/emux_hwdep.c
+++ b/sound/synth/emux/emux_hwdep.c
@@ -27,8 +27,7 @@ snd_emux_hwdep_load_patch(struct snd_emux *emu, void __user *arg)

 	if (patch.key == GUS_PATCH)
 		return snd_soundfont_load_guspatch(emu->sflist, arg,
-						   patch.len + sizeof(patch),
-						   TMP_CLIENT_ID);
+						   patch.len + sizeof(patch));

 	if (patch.type >= SNDRV_SFNT_LOAD_INFO &&
 	    patch.type <= SNDRV_SFNT_PROBE_DATA) {
diff --git a/sound/synth/emux/emux_oss.c b/sound/synth/emux/emux_oss.c
index d8d32671f703..04df46b269d3 100644
--- a/sound/synth/emux/emux_oss.c
+++ b/sound/synth/emux/emux_oss.c
@@ -205,8 +205,7 @@ snd_emux_load_patch_seq_oss(struct snd_seq_oss_arg *arg, int format,
 		return -ENXIO;

 	if (format == GUS_PATCH)
-		rc = snd_soundfont_load_guspatch(emu->sflist, buf, count,
-						 SF_CLIENT_NO(p->chset.port));
+		rc = snd_soundfont_load_guspatch(emu->sflist, buf, count);
 	else if (format == SNDRV_OSS_SOUNDFONT_PATCH) {
 		struct soundfont_patch_info patch;
 		if (count < (int)sizeof(patch))
diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c
index 16f00097cb95..e1e47518ac92 100644
--- a/sound/synth/emux/soundfont.c
+++ b/sound/synth/emux/soundfont.c
@@ -941,8 +941,7 @@ int snd_sf_vol_table[128] = {

 /* load GUS patch */
 static int
-load_guspatch(struct snd_sf_list *sflist, const char __user *data,
-	      long count, int client)
+load_guspatch(struct snd_sf_list *sflist, const char __user *data, long count)
 {
 	struct patch_info patch;
 	struct snd_soundfont *sf;
@@ -1122,11 +1121,11 @@ load_guspatch(struct snd_sf_list *sflist, const char __user *data,
 /* load GUS patch */
 int
 snd_soundfont_load_guspatch(struct snd_sf_list *sflist, const char __user *data,
-			    long count, int client)
+			    long count)
 {
 	int rc;
 	lock_preset(sflist);
-	rc = load_guspatch(sflist, data, count, client);
+	rc = load_guspatch(sflist, data, count);
 	unlock_preset(sflist);
 	return rc;
 }
--
2.42.0.419.g70bf8a5751


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 03/18] ALSA: emux: fix validation of snd_emux.num_ports
  2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 01/18] ALSA: emux: fix /proc teardown at module unload Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 02/18] ALSA: emux: prune unused parameter from snd_soundfont_load_guspatch() Oswald Buddenhagen
@ 2024-04-01 10:07 ` Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 04/18] ALSA: emux: fix init of patch_info.truesize in load_data() Oswald Buddenhagen
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 10:07 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Jaroslav Kysela, Arthur Marsh

Both bounds had off-by-one errors.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 sound/synth/emux/emux_seq.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/sound/synth/emux/emux_seq.c b/sound/synth/emux/emux_seq.c
index b227c7e0bc2a..1adaa75df2f6 100644
--- a/sound/synth/emux/emux_seq.c
+++ b/sound/synth/emux/emux_seq.c
@@ -65,11 +65,11 @@ snd_emux_init_seq(struct snd_emux *emu, struct snd_card *card, int index)
 		return -ENODEV;
 	}

-	if (emu->num_ports < 0) {
+	if (emu->num_ports <= 0) {
 		snd_printk(KERN_WARNING "seqports must be greater than zero\n");
 		emu->num_ports = 1;
-	} else if (emu->num_ports >= SNDRV_EMUX_MAX_PORTS) {
-		snd_printk(KERN_WARNING "too many ports."
+	} else if (emu->num_ports > SNDRV_EMUX_MAX_PORTS) {
+		snd_printk(KERN_WARNING "too many ports. "
 			   "limited max. ports %d\n", SNDRV_EMUX_MAX_PORTS);
 		emu->num_ports = SNDRV_EMUX_MAX_PORTS;
 	}
--
2.42.0.419.g70bf8a5751


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 04/18] ALSA: emux: fix init of patch_info.truesize in load_data()
  2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
                   ` (2 preceding siblings ...)
  2024-04-01 10:07 ` [PATCH 03/18] ALSA: emux: fix validation of snd_emux.num_ports Oswald Buddenhagen
@ 2024-04-01 10:07 ` Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 05/18] ALSA: emu10k1: prune vestiges of SNDRV_SFNT_SAMPLE_{BIDIR,REVERSE}_LOOP support Oswald Buddenhagen
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 10:07 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Jaroslav Kysela, Arthur Marsh

The field is explicitly documented to be initialized by the driver
(which it actually is). Also, using patch_info.size would be actually
wrong for 16-bit data, as one field counts samples, while the other
counts bytes.

load_guspatch() already did it right.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 sound/synth/emux/soundfont.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c
index e1e47518ac92..ad0231d7a39d 100644
--- a/sound/synth/emux/soundfont.c
+++ b/sound/synth/emux/soundfont.c
@@ -735,7 +735,7 @@ load_data(struct snd_sf_list *sflist, const void __user *data, long count)
 	sp->v = sample_info;
 	sp->v.sf_id = sf->id;
 	sp->v.dummy = 0;
-	sp->v.truesize = sp->v.size;
+	sp->v.truesize = 0;

 	/*
 	 * If there is wave data then load it.
--
2.42.0.419.g70bf8a5751


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 05/18] ALSA: emu10k1: prune vestiges of SNDRV_SFNT_SAMPLE_{BIDIR,REVERSE}_LOOP support
  2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
                   ` (3 preceding siblings ...)
  2024-04-01 10:07 ` [PATCH 04/18] ALSA: emux: fix init of patch_info.truesize in load_data() Oswald Buddenhagen
@ 2024-04-01 10:07 ` Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 06/18] ALSA: emux: centralize & improve patch info validation Oswald Buddenhagen
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 10:07 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Jaroslav Kysela, Arthur Marsh

This is required only to implement WAVE_BIDIR_LOOP and WAVE_LOOP_BACK in
the GUS patch loader. It has not worked on emu10k1 since before ALSA hit
mainline, yet nobody appears to have complained. And as it isn't super
easy to implement, just admit defeat and clean up the code.

If somebody wanted to resurrect the feature, the emu8k driver could
serve as a template, but the code would be quite different. But
arguably, this should be done in user space in the first place, as this
doesn't represent a hardware feature (somewhat ironically, the actual
GUS driver has no synth support, and therefore no GUS patch loader).

Note that instead of properly rejecting affected samples, we continue to
just pretend that the feature wasn't requested. This is extremely
questionable behavior, but avoids that possibly unused instruments
suddenly prevent loading the entire file, which would break backwards
compatibility. But at least we log a warning now.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 sound/pci/emu10k1/emu10k1_patch.c | 73 ++++---------------------------
 1 file changed, 8 insertions(+), 65 deletions(-)

diff --git a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c
index 89890f24509f..49214c226808 100644
--- a/sound/pci/emu10k1/emu10k1_patch.c
+++ b/sound/pci/emu10k1/emu10k1_patch.c
@@ -28,8 +28,6 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 {
 	int offset;
 	int truesize, size, blocksize;
-	__maybe_unused int loopsize;
-	int loopend, sampleend;
 	unsigned int start_addr;
 	struct snd_emu10k1 *emu;

@@ -43,32 +41,24 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 		return 0;
 	}

+	if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP | SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) {
+		/* should instead return -ENOTSUPP; but compatibility */
+		printk(KERN_WARNING "Emu10k1 wavetable patch %d with unsupported loop feature\n",
+		       sp->v.sample);
+	}
+
 	/* recalculate address offset */
 	sp->v.end -= sp->v.start;
 	sp->v.loopstart -= sp->v.start;
 	sp->v.loopend -= sp->v.start;
 	sp->v.start = 0;

-	/* some samples have invalid data.  the addresses are corrected in voice info */
-	sampleend = sp->v.end;
-	if (sampleend > sp->v.size)
-		sampleend = sp->v.size;
-	loopend = sp->v.loopend;
-	if (loopend > sampleend)
-		loopend = sampleend;
-
 	/* be sure loop points start < end */
 	if (sp->v.loopstart >= sp->v.loopend)
 		swap(sp->v.loopstart, sp->v.loopend);

 	/* compute true data size to be loaded */
 	truesize = sp->v.size + BLANK_HEAD_SIZE;
-	loopsize = 0;
-#if 0 /* not supported */
-	if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP))
-		loopsize = sp->v.loopend - sp->v.loopstart;
-	truesize += loopsize;
-#endif
 	if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK)
 		truesize += BLANK_LOOP_SIZE;

@@ -96,65 +86,18 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 	snd_emu10k1_synth_bzero(emu, sp->block, offset, size);
 	offset += size;

-	/* copy start->loopend */
-	size = loopend;
+	/* copy provided samples */
+	size = sp->v.size;
 	if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
 		size *= 2;
 	if (offset + size > blocksize)
 		return -EINVAL;
 	if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
 		snd_emu10k1_synth_free(emu, sp->block);
 		sp->block = NULL;
 		return -EFAULT;
 	}
 	offset += size;
-	data += size;
-
-#if 0 /* not supported yet */
-	/* handle reverse (or bidirectional) loop */
-	if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) {
-		/* copy loop in reverse */
-		if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) {
-			int woffset;
-			unsigned short *wblock = (unsigned short*)block;
-			woffset = offset / 2;
-			if (offset + loopsize * 2 > blocksize)
-				return -EINVAL;
-			for (i = 0; i < loopsize; i++)
-				wblock[woffset + i] = wblock[woffset - i -1];
-			offset += loopsize * 2;
-		} else {
-			if (offset + loopsize > blocksize)
-				return -EINVAL;
-			for (i = 0; i < loopsize; i++)
-				block[offset + i] = block[offset - i -1];
-			offset += loopsize;
-		}
-
-		/* modify loop pointers */
-		if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_BIDIR_LOOP) {
-			sp->v.loopend += loopsize;
-		} else {
-			sp->v.loopstart += loopsize;
-			sp->v.loopend += loopsize;
-		}
-		/* add sample pointer */
-		sp->v.end += loopsize;
-	}
-#endif
-
-	/* loopend -> sample end */
-	size = sp->v.size - loopend;
-	if (size < 0)
-		return -EINVAL;
-	if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
-		size *= 2;
-	if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
-		snd_emu10k1_synth_free(emu, sp->block);
-		sp->block = NULL;
-		return -EFAULT;
-	}
-	offset += size;

 	/* clear rest of samples (if any) */
 	if (offset < blocksize)
--
2.42.0.419.g70bf8a5751


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 06/18] ALSA: emux: centralize & improve patch info validation
  2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
                   ` (4 preceding siblings ...)
  2024-04-01 10:07 ` [PATCH 05/18] ALSA: emu10k1: prune vestiges of SNDRV_SFNT_SAMPLE_{BIDIR,REVERSE}_LOOP support Oswald Buddenhagen
@ 2024-04-01 10:07 ` Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 07/18] ALSA: emux: improve patch ioctl data validation Oswald Buddenhagen
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 10:07 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Jaroslav Kysela, Arthur Marsh

This does several closely related things:
- Move the code from the drivers into the SoundFont loader, which
  de-duplicates it.
- Sort of explain the weird "recalculate address offset" feature. Note
  that I don't think it actually makes any sense - the calling user
  space code should do that. The background is certainly that the source
  data (the SoundFont format) uses pointers into a single wave block
  (and the API allows doing the same for on-board ROM), but the API
  expects the wave data from user space to be pre-chopped into
  individual patches anyway.
- Make sure that the specified offsets actually lie within the supplied
  wave data. Note that we don't validate ROM offsets, so one can play
  back anything within the sound card's address space.
- In load_guspatch(), don't call the sample_new callback anymore when
  the patch size is zero, as was already the case in load_data(). The
  callbacks would instantly return in that case anyway; these checks are
  now removed.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 sound/isa/sb/emu8000_patch.c      | 13 -----------
 sound/pci/emu10k1/emu10k1_patch.c | 16 -------------
 sound/synth/emux/soundfont.c      | 37 ++++++++++++++++++++++++++++++-
 3 files changed, 36 insertions(+), 30 deletions(-)

diff --git a/sound/isa/sb/emu8000_patch.c b/sound/isa/sb/emu8000_patch.c
index 8c1e7f2bfc34..ab4f988f080d 100644
--- a/sound/isa/sb/emu8000_patch.c
+++ b/sound/isa/sb/emu8000_patch.c
@@ -148,13 +148,6 @@ snd_emu8000_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 	if (snd_BUG_ON(!sp))
 		return -EINVAL;

-	if (sp->v.size == 0)
-		return 0;
-
-	/* be sure loop points start < end */
-	if (sp->v.loopstart > sp->v.loopend)
-		swap(sp->v.loopstart, sp->v.loopend);
-
 	/* compute true data size to be loaded */
 	truesize = sp->v.size;
 	if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP))
@@ -177,12 +170,6 @@ snd_emu8000_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 			return -EFAULT;
 	}

-	/* recalculate address offset */
-	sp->v.end -= sp->v.start;
-	sp->v.loopstart -= sp->v.start;
-	sp->v.loopend -= sp->v.start;
-	sp->v.start = 0;
-
 	/* dram position (in word) -- mem_offset is byte */
 	dram_offset = EMU8000_DRAM_OFFSET + (sp->block->offset >> 1);
 	dram_start = dram_offset;
diff --git a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c
index 49214c226808..47d69a0e44bc 100644
--- a/sound/pci/emu10k1/emu10k1_patch.c
+++ b/sound/pci/emu10k1/emu10k1_patch.c
@@ -35,28 +35,12 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 	if (snd_BUG_ON(!sp || !hdr))
 		return -EINVAL;

-	if (sp->v.size == 0) {
-		dev_dbg(emu->card->dev,
-			"emu: rom font for sample %d\n", sp->v.sample);
-		return 0;
-	}
-
 	if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP | SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) {
 		/* should instead return -ENOTSUPP; but compatibility */
 		printk(KERN_WARNING "Emu10k1 wavetable patch %d with unsupported loop feature\n",
 		       sp->v.sample);
 	}

-	/* recalculate address offset */
-	sp->v.end -= sp->v.start;
-	sp->v.loopstart -= sp->v.start;
-	sp->v.loopend -= sp->v.start;
-	sp->v.start = 0;
-
-	/* be sure loop points start < end */
-	if (sp->v.loopstart >= sp->v.loopend)
-		swap(sp->v.loopstart, sp->v.loopend);
-
 	/* compute true data size to be loaded */
 	truesize = sp->v.size + BLANK_HEAD_SIZE;
 	if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK)
diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c
index ad0231d7a39d..6d6f0102ed5b 100644
--- a/sound/synth/emux/soundfont.c
+++ b/sound/synth/emux/soundfont.c
@@ -689,6 +689,21 @@ find_sample(struct snd_soundfont *sf, int sample_id)
 }


+static int
+validate_sample_info(struct soundfont_sample_info *si)
+{
+	if (si->end < 0 || si->end > si->size)
+		return -EINVAL;
+	if (si->loopstart < 0 || si->loopstart > si->end)
+		return -EINVAL;
+	if (si->loopend < 0 || si->loopend > si->end)
+		return -EINVAL;
+	/* be sure loop points start < end */
+	if (si->loopstart > si->loopend)
+		swap(si->loopstart, si->loopend);
+	return 0;
+}
+
 /*
  * Load sample information, this can include data to be loaded onto
  * the soundcard.  It can also just be a pointer into soundcard ROM.
@@ -727,6 +742,21 @@ load_data(struct snd_sf_list *sflist, const void __user *data, long count)
 		return -EINVAL;
 	}

+	if (sample_info.size > 0) {
+		if (sample_info.start < 0)
+			return -EINVAL;
+
+		// Here we "rebase out" the start address, because the
+		// real start is the start of the provided sample data.
+		sample_info.end -= sample_info.start;
+		sample_info.loopstart -= sample_info.start;
+		sample_info.loopend -= sample_info.start;
+		sample_info.start = 0;
+
+		if (validate_sample_info(&sample_info) < 0)
+			return -EINVAL;
+	}
+
 	/* Allocate a new sample structure */
 	sp = sf_sample_new(sflist, sf);
 	if (!sp)
@@ -974,6 +1004,11 @@ load_guspatch(struct snd_sf_list *sflist, const char __user *data, long count)
 	smp->v.loopend = patch.loop_end;
 	smp->v.size = patch.len;

+	if (validate_sample_info(&smp->v) < 0) {
+		sf_sample_delete(sflist, sf, smp);
+		return -EINVAL;
+	}
+
 	/* set up mode flags */
 	smp->v.mode_flags = 0;
 	if (!(patch.mode & WAVE_16_BITS))
@@ -1011,7 +1046,7 @@ load_guspatch(struct snd_sf_list *sflist, const char __user *data, long count)
 	/*
 	 * load wave data
 	 */
-	if (sflist->callback.sample_new) {
+	if (smp->v.size > 0 && sflist->callback.sample_new) {
 		rc = sflist->callback.sample_new
 			(sflist->callback.private_data, smp, sflist->memhdr,
 			 data, count);
--
2.42.0.419.g70bf8a5751


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 07/18] ALSA: emux: improve patch ioctl data validation
  2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
                   ` (5 preceding siblings ...)
  2024-04-01 10:07 ` [PATCH 06/18] ALSA: emux: centralize & improve patch info validation Oswald Buddenhagen
@ 2024-04-01 10:07 ` Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 08/18] ALSA: emu10k1: move patch loader assertions into low-level functions Oswald Buddenhagen
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 10:07 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Jaroslav Kysela, Arthur Marsh

In load_data(), make the validation of and skipping over the main info
block match that in load_guspatch().

In load_guspatch(), add checking that the specified patch length matches
the actually supplied data, like load_data() already did.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 sound/synth/emux/soundfont.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c
index 6d6f0102ed5b..4edc693da8e7 100644
--- a/sound/synth/emux/soundfont.c
+++ b/sound/synth/emux/soundfont.c
@@ -716,22 +716,25 @@ load_data(struct snd_sf_list *sflist, const void __user *data, long count)
 	struct snd_soundfont *sf;
 	struct soundfont_sample_info sample_info;
 	struct snd_sf_sample *sp;
-	long off;

 	/* patch must be opened */
 	sf = sflist->currsf;
 	if (!sf)
 		return -EINVAL;

 	if (is_special_type(sf->type))
 		return -EINVAL;

+	if (count < (long)sizeof(sample_info)) {
+		return -EINVAL;
+	}
 	if (copy_from_user(&sample_info, data, sizeof(sample_info)))
 		return -EFAULT;
+	data += sizeof(sample_info);
+	count -= sizeof(sample_info);

-	off = sizeof(sample_info);
-
-	if (sample_info.size != (count-off)/2)
+	// SoundFont uses S16LE samples.
+	if (sample_info.size * 2 != count)
 		return -EINVAL;

 	/* Check for dup */
@@ -774,7 +777,7 @@ load_data(struct snd_sf_list *sflist, const void __user *data, long count)
 		int  rc;
 		rc = sflist->callback.sample_new
 			(sflist->callback.private_data, sp, sflist->memhdr,
-			 data + off, count - off);
+			 data, count);
 		if (rc < 0) {
 			sf_sample_delete(sflist, sf, sp);
 			return rc;
@@ -986,10 +989,12 @@ load_guspatch(struct snd_sf_list *sflist, const char __user *data, long count)
 	}
 	if (copy_from_user(&patch, data, sizeof(patch)))
 		return -EFAULT;
-
 	count -= sizeof(patch);
 	data += sizeof(patch);

+	if ((patch.len << (patch.mode & WAVE_16_BITS ? 1 : 0)) != count)
+		return -EINVAL;
+
 	sf = newsf(sflist, SNDRV_SFNT_PAT_TYPE_GUS|SNDRV_SFNT_PAT_SHARED, NULL);
 	if (sf == NULL)
 		return -ENOMEM;
--
2.42.0.419.g70bf8a5751


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 08/18] ALSA: emu10k1: move patch loader assertions into low-level functions
  2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
                   ` (6 preceding siblings ...)
  2024-04-01 10:07 ` [PATCH 07/18] ALSA: emux: improve patch ioctl data validation Oswald Buddenhagen
@ 2024-04-01 10:07 ` Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 09/18] ALSA: emu10k1: fix sample signedness issues in wavetable loader Oswald Buddenhagen
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 10:07 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Jaroslav Kysela, Arthur Marsh

Convert some checks in snd_emu10k1_sample_new() back into assertions (as
they were prior to da3cec35dd (ALSA: Kill snd_assert() in sound/pci/*,
2008-08-08)), and move them into the low-level memory access functions
they protect.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>

---

Side note: this eliminates the memory leaks in the now gone error paths.
I don't think it was actually possible to trigger these even before the
foregoing cleanups. But if it were, it would allow a user with access to
the audio device a scope-limited DoS attack on it. This would be only a
very minor security hole, given that on modern systems it would merely
enable the current seat owner to be a nuisance to their successor, by
making a reboot necessary.
---
 sound/pci/emu10k1/emu10k1_patch.c | 4 ----
 sound/pci/emu10k1/memory.c        | 6 ++++++
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c
index 47d69a0e44bc..55bb60d31fe4 100644
--- a/sound/pci/emu10k1/emu10k1_patch.c
+++ b/sound/pci/emu10k1/emu10k1_patch.c
@@ -65,17 +65,13 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 	size = BLANK_HEAD_SIZE;
 	if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
 		size *= 2;
-	if (offset + size > blocksize)
-		return -EINVAL;
 	snd_emu10k1_synth_bzero(emu, sp->block, offset, size);
 	offset += size;

 	/* copy provided samples */
 	size = sp->v.size;
 	if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
 		size *= 2;
-	if (offset + size > blocksize)
-		return -EINVAL;
 	if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
 		snd_emu10k1_synth_free(emu, sp->block);
 		sp->block = NULL;
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c
index 20b07117574b..fc9444404151 100644
--- a/sound/pci/emu10k1/memory.c
+++ b/sound/pci/emu10k1/memory.c
@@ -574,6 +574,9 @@ int snd_emu10k1_synth_bzero(struct snd_emu10k1 *emu, struct snd_util_memblk *blk
 	void *ptr;
 	struct snd_emu10k1_memblk *p = (struct snd_emu10k1_memblk *)blk;

+	if (snd_BUG_ON(offset + size > p->mem.size))
+		return -EFAULT;
+
 	offset += blk->offset & (PAGE_SIZE - 1);
 	end_offset = offset + size;
 	page = get_aligned_page(offset);
@@ -604,6 +607,9 @@ int snd_emu10k1_synth_copy_from_user(struct snd_emu10k1 *emu, struct snd_util_me
 	void *ptr;
 	struct snd_emu10k1_memblk *p = (struct snd_emu10k1_memblk *)blk;

+	if (snd_BUG_ON(offset + size > p->mem.size))
+		return -EFAULT;
+
 	offset += blk->offset & (PAGE_SIZE - 1);
 	end_offset = offset + size;
 	page = get_aligned_page(offset);
--
2.42.0.419.g70bf8a5751


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 09/18] ALSA: emu10k1: fix sample signedness issues in wavetable loader
  2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
                   ` (7 preceding siblings ...)
  2024-04-01 10:07 ` [PATCH 08/18] ALSA: emu10k1: move patch loader assertions into low-level functions Oswald Buddenhagen
@ 2024-04-01 10:07 ` Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 10/18] ALSA: emu10k1: fix playback of 8-bit wavetable samples Oswald Buddenhagen
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 10:07 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Jaroslav Kysela, Arthur Marsh

The hardware supports S16LE and U8 samples, while U16LE and S8 (which
the driver implicitly claims to support) require sign flipping.

Note that this matters only for the GUS patch loader, as the implemented
SoundFont v2.01 spec is limited to S16LE.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 include/sound/emu10k1.h           |  4 +--
 sound/pci/emu10k1/emu10k1_patch.c | 30 ++++++++-----------
 sound/pci/emu10k1/memory.c        | 49 +++++++++++++++++++++++++------
 3 files changed, 55 insertions(+), 28 deletions(-)

diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 1af9e6819392..9e3bd4f81460 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -1882,8 +1882,8 @@ int snd_emu10k1_alloc_pages_maybe_wider(struct snd_emu10k1 *emu, size_t size,
 					struct snd_dma_buffer *dmab);
 struct snd_util_memblk *snd_emu10k1_synth_alloc(struct snd_emu10k1 *emu, unsigned int size);
 int snd_emu10k1_synth_free(struct snd_emu10k1 *emu, struct snd_util_memblk *blk);
-int snd_emu10k1_synth_bzero(struct snd_emu10k1 *emu, struct snd_util_memblk *blk, int offset, int size);
-int snd_emu10k1_synth_copy_from_user(struct snd_emu10k1 *emu, struct snd_util_memblk *blk, int offset, const char __user *data, int size);
+int snd_emu10k1_synth_memset(struct snd_emu10k1 *emu, struct snd_util_memblk *blk, int offset, int size, u8 value);
+int snd_emu10k1_synth_copy_from_user(struct snd_emu10k1 *emu, struct snd_util_memblk *blk, int offset, const char __user *data, int size, u32 xor);
 int snd_emu10k1_memblk_map(struct snd_emu10k1 *emu, struct snd_emu10k1_memblk *blk);

 /* voice allocation */
diff --git a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c
index 55bb60d31fe4..eb3d1ef8a33a 100644
--- a/sound/pci/emu10k1/emu10k1_patch.c
+++ b/sound/pci/emu10k1/emu10k1_patch.c
@@ -26,6 +26,8 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 		       struct snd_util_memhdr *hdr,
 		       const void __user *data, long count)
 {
+	u8 fill;
+	u32 xor;
 	int offset;
 	int truesize, size, blocksize;
 	unsigned int start_addr;
@@ -41,6 +43,14 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 		       sp->v.sample);
 	}

+	if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS) {
+		fill = 0x80;
+		xor = (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) ? 0 : 0x80808080;
+	} else {
+		fill = 0;
+		xor = (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) ? 0x80008000 : 0;
+	}
+
 	/* compute true data size to be loaded */
 	truesize = sp->v.size + BLANK_HEAD_SIZE;
 	if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK)
@@ -65,46 +75,32 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 	size = BLANK_HEAD_SIZE;
 	if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
 		size *= 2;
-	snd_emu10k1_synth_bzero(emu, sp->block, offset, size);
+	snd_emu10k1_synth_memset(emu, sp->block, offset, size, fill);
 	offset += size;

 	/* copy provided samples */
 	size = sp->v.size;
 	if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
 		size *= 2;
-	if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size)) {
+	if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor)) {
 		snd_emu10k1_synth_free(emu, sp->block);
 		sp->block = NULL;
 		return -EFAULT;
 	}
 	offset += size;

 	/* clear rest of samples (if any) */
 	if (offset < blocksize)
-		snd_emu10k1_synth_bzero(emu, sp->block, offset, blocksize - offset);
+		snd_emu10k1_synth_memset(emu, sp->block, offset, blocksize - offset, fill);

 	if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) {
 		/* if no blank loop is attached in the sample, add it */
 		if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) {
 			sp->v.loopstart = sp->v.end + BLANK_LOOP_START;
 			sp->v.loopend = sp->v.end + BLANK_LOOP_END;
 		}
 	}

-#if 0 /* not supported yet */
-	if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) {
-		/* unsigned -> signed */
-		if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS)) {
-			unsigned short *wblock = (unsigned short*)block;
-			for (i = 0; i < truesize; i++)
-				wblock[i] ^= 0x8000;
-		} else {
-			for (i = 0; i < truesize; i++)
-				block[i] ^= 0x80;
-		}
-	}
-#endif
-
 	/* recalculate offset */
 	start_addr = BLANK_HEAD_SIZE * 2;
 	if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c
index fc9444404151..d29711777161 100644
--- a/sound/pci/emu10k1/memory.c
+++ b/sound/pci/emu10k1/memory.c
@@ -565,10 +565,10 @@ static inline void *offset_ptr(struct snd_emu10k1 *emu, int page, int offset)
 }

 /*
- * bzero(blk + offset, size)
+ * memset(blk + offset, value, size)
  */
-int snd_emu10k1_synth_bzero(struct snd_emu10k1 *emu, struct snd_util_memblk *blk,
-			    int offset, int size)
+int snd_emu10k1_synth_memset(struct snd_emu10k1 *emu, struct snd_util_memblk *blk,
+			     int offset, int size, u8 value)
 {
 	int page, nextofs, end_offset, temp, temp1;
 	void *ptr;
@@ -588,20 +588,47 @@ int snd_emu10k1_synth_bzero(struct snd_emu10k1 *emu, struct snd_util_memblk *blk
 			temp = temp1;
 		ptr = offset_ptr(emu, page + p->first_page, offset);
 		if (ptr)
-			memset(ptr, 0, temp);
+			memset(ptr, value, temp);
 		offset = nextofs;
 		page++;
 	} while (offset < end_offset);
 	return 0;
 }

-EXPORT_SYMBOL(snd_emu10k1_synth_bzero);
+EXPORT_SYMBOL(snd_emu10k1_synth_memset);
+
+// Note that the value is assumed to be suitably repetitive.
+static void xor_range(void *ptr, int size, u32 value)
+{
+	if ((long)ptr & 1) {
+		*(u8 *)ptr ^= (u8)value;
+		ptr++;
+		size--;
+	}
+	if (size > 1 && ((long)ptr & 2)) {
+		*(u16 *)ptr ^= (u16)value;
+		ptr += 2;
+		size -= 2;
+	}
+	while (size > 3) {
+		*(u32 *)ptr ^= value;
+		ptr += 4;
+		size -= 4;
+	}
+	if (size > 1) {
+		*(u16 *)ptr ^= (u16)value;
+		ptr += 2;
+		size -= 2;
+	}
+	if (size > 0)
+		*(u8 *)ptr ^= (u8)value;
+}

 /*
- * copy_from_user(blk + offset, data, size)
+ * copy_from_user(blk + offset, data, size) ^ xor
  */
 int snd_emu10k1_synth_copy_from_user(struct snd_emu10k1 *emu, struct snd_util_memblk *blk,
-				     int offset, const char __user *data, int size)
+				     int offset, const char __user *data, int size, u32 xor)
 {
 	int page, nextofs, end_offset, temp, temp1;
 	void *ptr;
@@ -620,8 +647,12 @@ int snd_emu10k1_synth_copy_from_user(struct snd_emu10k1 *emu, struct snd_util_me
 		if (temp1 < temp)
 			temp = temp1;
 		ptr = offset_ptr(emu, page + p->first_page, offset);
-		if (ptr && copy_from_user(ptr, data, temp))
-			return -EFAULT;
+		if (ptr) {
+			if (copy_from_user(ptr, data, temp))
+				return -EFAULT;
+			if (xor)
+				xor_range(ptr, temp, xor);
+		}
 		offset = nextofs;
 		data += temp;
 		page++;
--
2.42.0.419.g70bf8a5751


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 10/18] ALSA: emu10k1: fix playback of 8-bit wavetable samples
  2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
                   ` (8 preceding siblings ...)
  2024-04-01 10:07 ` [PATCH 09/18] ALSA: emu10k1: fix sample signedness issues in wavetable loader Oswald Buddenhagen
@ 2024-04-01 10:07 ` Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 11/18] ALSA: emu10k1: make wavetable sample playback start position exact Oswald Buddenhagen
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 10:07 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Jaroslav Kysela, Arthur Marsh

Samples are byte-sized in this mode, and thus the offset calculation
needs no shifting.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 sound/pci/emu10k1/emu10k1_callback.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c
index d36234b88fb4..2ed72bea1d8f 100644
--- a/sound/pci/emu10k1/emu10k1_callback.c
+++ b/sound/pci/emu10k1/emu10k1_callback.c
@@ -310,27 +310,29 @@ start_voice(struct snd_emux_voice *vp)
 {
 	unsigned int temp;
 	int ch;
+	bool w_16;
 	u32 psst, dsl, map, ccca, vtarget;
 	unsigned int addr, mapped_offset;
 	struct snd_midi_channel *chan;
 	struct snd_emu10k1 *hw;
 	struct snd_emu10k1_memblk *emem;

 	hw = vp->hw;
 	ch = vp->ch;
 	if (snd_BUG_ON(ch < 0))
 		return -EINVAL;
 	chan = vp->chan;
+	w_16 = !(vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_8BITS);

 	emem = (struct snd_emu10k1_memblk *)vp->block;
 	if (emem == NULL)
 		return -EINVAL;
 	emem->map_locked++;
 	if (snd_emu10k1_memblk_map(hw, emem) < 0) {
 		/* dev_err(hw->card->devK, "emu: cannot map!\n"); */
 		return -ENOMEM;
 	}
-	mapped_offset = snd_emu10k1_memblk_offset(emem) >> 1;
+	mapped_offset = snd_emu10k1_memblk_offset(emem) >> w_16;
 	vp->reg.start += mapped_offset;
 	vp->reg.end += mapped_offset;
 	vp->reg.loopstart += mapped_offset;
@@ -371,7 +373,7 @@ start_voice(struct snd_emux_voice *vp)
 		unsigned int shift = (vp->apitch - 0xe000) >> 10;
 		ccca |= shift << 25;
 	}
-	if (vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_8BITS)
+	if (!w_16)
 		ccca |= CCCA_8BITSELECT;

 	vtarget = (unsigned int)vp->vtarget << 16;
--
2.42.0.419.g70bf8a5751


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 11/18] ALSA: emu10k1: make wavetable sample playback start position exact
  2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
                   ` (9 preceding siblings ...)
  2024-04-01 10:07 ` [PATCH 10/18] ALSA: emu10k1: fix playback of 8-bit wavetable samples Oswald Buddenhagen
@ 2024-04-01 10:07 ` Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 12/18] ALSA: emu10k1: shrink blank space in front of wavetable samples Oswald Buddenhagen
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 10:07 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Jaroslav Kysela, Arthur Marsh

This amends df335e9a8b (ALSA: emu10k1: fix synthesizer sample playback
position and caching, 2023-05-18), because now I know that the samples
are preceded by a blank block anyway, so we can just compensate for the
interpolator read-ahead without any additional fiddling.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 sound/pci/emu10k1/emu10k1_callback.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c
index 2ed72bea1d8f..ef26e4d3e2a3 100644
--- a/sound/pci/emu10k1/emu10k1_callback.c
+++ b/sound/pci/emu10k1/emu10k1_callback.c
@@ -255,7 +255,7 @@ lookup_voices(struct snd_emux *emu, struct snd_emu10k1 *hw,
 		/* check if sample is finished playing (non-looping only) */
 		if (bp != best + V_OFF && bp != best + V_FREE &&
 		    (vp->reg.sample_mode & SNDRV_SFNT_SAMPLE_SINGLESHOT)) {
-			val = snd_emu10k1_ptr_read(hw, CCCA_CURRADDR, vp->ch) - 64;
+			val = snd_emu10k1_ptr_read(hw, CCCA_CURRADDR, vp->ch) - 64 + 3;
 			if (val >= vp->reg.loopstart)
 				bp = best + V_OFF;
 		}
@@ -364,7 +364,7 @@ start_voice(struct snd_emux_voice *vp)

 	map = (hw->silent_page.addr << hw->address_mode) | (hw->address_mode ? MAP_PTI_MASK1 : MAP_PTI_MASK0);

-	addr = vp->reg.start + 64;
+	addr = vp->reg.start + 64 - 3;
 	temp = vp->reg.parm.filterQ;
 	ccca = (temp << 28) | addr;
 	if (vp->apitch < 0xe400)
--
2.42.0.419.g70bf8a5751


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 12/18] ALSA: emu10k1: shrink blank space in front of wavetable samples
  2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
                   ` (10 preceding siblings ...)
  2024-04-01 10:07 ` [PATCH 11/18] ALSA: emu10k1: make wavetable sample playback start position exact Oswald Buddenhagen
@ 2024-04-01 10:07 ` Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 13/18] ALSA: emu10k1: merge conditions in patch loader Oswald Buddenhagen
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 10:07 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Jaroslav Kysela, Arthur Marsh

There is no need for it to be 32 samples - 3 will do just fine (which is
the interpolator's epsilon). The old size was presumably meant to
compensate for the cache's presence, but we're now handling that
properly.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 sound/pci/emu10k1/emu10k1_patch.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c
index eb3d1ef8a33a..a2ba6246dbc7 100644
--- a/sound/pci/emu10k1/emu10k1_patch.c
+++ b/sound/pci/emu10k1/emu10k1_patch.c
@@ -16,7 +16,7 @@
 #define BLANK_LOOP_START	4
 #define BLANK_LOOP_END		8
 #define BLANK_LOOP_SIZE		12
-#define BLANK_HEAD_SIZE		32
+#define BLANK_HEAD_SIZE		3

 /*
  * allocate a sample block and copy data from userspace
--
2.42.0.419.g70bf8a5751


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 13/18] ALSA: emu10k1: merge conditions in patch loader
  2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
                   ` (11 preceding siblings ...)
  2024-04-01 10:07 ` [PATCH 12/18] ALSA: emu10k1: shrink blank space in front of wavetable samples Oswald Buddenhagen
@ 2024-04-01 10:07 ` Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 14/18] ALSA: emu10k1: fix wavetable offset recalculation Oswald Buddenhagen
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 10:07 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Jaroslav Kysela, Arthur Marsh

This de-duplicates the code slightly. But the real reason is that it
moves the code up, which the next patch will depend on.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 sound/pci/emu10k1/emu10k1_patch.c | 16 +++++++---------
 1 file changed, 7 insertions(+), 9 deletions(-)

diff --git a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c
index a2ba6246dbc7..c7d54f38d28c 100644
--- a/sound/pci/emu10k1/emu10k1_patch.c
+++ b/sound/pci/emu10k1/emu10k1_patch.c
@@ -53,8 +53,14 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,

 	/* compute true data size to be loaded */
 	truesize = sp->v.size + BLANK_HEAD_SIZE;
-	if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK)
+	if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) {
 		truesize += BLANK_LOOP_SIZE;
+		/* if no blank loop is attached in the sample, add it */
+		if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) {
+			sp->v.loopstart = sp->v.end + BLANK_LOOP_START;
+			sp->v.loopend = sp->v.end + BLANK_LOOP_END;
+		}
+	}

 	/* try to allocate a memory block */
 	blocksize = truesize;
@@ -93,14 +99,6 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 	if (offset < blocksize)
 		snd_emu10k1_synth_memset(emu, sp->block, offset, blocksize - offset, fill);

-	if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_NO_BLANK) {
-		/* if no blank loop is attached in the sample, add it */
-		if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_SINGLESHOT) {
-			sp->v.loopstart = sp->v.end + BLANK_LOOP_START;
-			sp->v.loopend = sp->v.end + BLANK_LOOP_END;
-		}
-	}
-
 	/* recalculate offset */
 	start_addr = BLANK_HEAD_SIZE * 2;
 	if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
--
2.42.0.419.g70bf8a5751


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 14/18] ALSA: emu10k1: fix wavetable offset recalculation
  2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
                   ` (12 preceding siblings ...)
  2024-04-01 10:07 ` [PATCH 13/18] ALSA: emu10k1: merge conditions in patch loader Oswald Buddenhagen
@ 2024-04-01 10:07 ` Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 15/18] ALSA: emu10k1: de-duplicate size calculations for 16-bit samples Oswald Buddenhagen
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 10:07 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Jaroslav Kysela, Arthur Marsh

The offsets are counted in samples, not in bytes.

While the code block is being rewritten, also move it up a bit, to avoid
churn in a subsequent patch.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 sound/pci/emu10k1/emu10k1_patch.c | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c
index c7d54f38d28c..eb8365650bd4 100644
--- a/sound/pci/emu10k1/emu10k1_patch.c
+++ b/sound/pci/emu10k1/emu10k1_patch.c
@@ -30,7 +30,6 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 	u32 xor;
 	int offset;
 	int truesize, size, blocksize;
-	unsigned int start_addr;
 	struct snd_emu10k1 *emu;

 	emu = rec->hw;
@@ -62,6 +61,12 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 		}
 	}

+	/* recalculate offset */
+	sp->v.start += BLANK_HEAD_SIZE;
+	sp->v.end += BLANK_HEAD_SIZE;
+	sp->v.loopstart += BLANK_HEAD_SIZE;
+	sp->v.loopend += BLANK_HEAD_SIZE;
+
 	/* try to allocate a memory block */
 	blocksize = truesize;
 	if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
@@ -99,15 +104,6 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 	if (offset < blocksize)
 		snd_emu10k1_synth_memset(emu, sp->block, offset, blocksize - offset, fill);

-	/* recalculate offset */
-	start_addr = BLANK_HEAD_SIZE * 2;
-	if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
-		start_addr >>= 1;
-	sp->v.start += start_addr;
-	sp->v.end += start_addr;
-	sp->v.loopstart += start_addr;
-	sp->v.loopend += start_addr;
-
 	return 0;
 }

--
2.42.0.419.g70bf8a5751


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 15/18] ALSA: emu10k1: de-duplicate size calculations for 16-bit samples
  2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
                   ` (13 preceding siblings ...)
  2024-04-01 10:07 ` [PATCH 14/18] ALSA: emu10k1: fix wavetable offset recalculation Oswald Buddenhagen
@ 2024-04-01 10:07 ` Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 16/18] ALSA: emu10k1: improve cache behavior documentation Oswald Buddenhagen
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 10:07 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Jaroslav Kysela, Arthur Marsh

Instead of repeatedly checking the sample width, assign a size shift
centrally.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 sound/pci/emu10k1/emu10k1_patch.c | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c
index eb8365650bd4..699aa0fec97b 100644
--- a/sound/pci/emu10k1/emu10k1_patch.c
+++ b/sound/pci/emu10k1/emu10k1_patch.c
@@ -28,6 +28,7 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 {
 	u8 fill;
 	u32 xor;
+	int shift;
 	int offset;
 	int truesize, size, blocksize;
 	struct snd_emu10k1 *emu;
@@ -43,9 +44,11 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 	}

 	if (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS) {
+		shift = 0;
 		fill = 0x80;
 		xor = (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) ? 0 : 0x80808080;
 	} else {
+		shift = 1;
 		fill = 0;
 		xor = (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_UNSIGNED) ? 0x80008000 : 0;
 	}
@@ -68,9 +71,7 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 	sp->v.loopend += BLANK_HEAD_SIZE;

 	/* try to allocate a memory block */
-	blocksize = truesize;
-	if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
-		blocksize *= 2;
+	blocksize = truesize << shift;
 	sp->block = snd_emu10k1_synth_alloc(emu, blocksize);
 	if (sp->block == NULL) {
 		dev_dbg(emu->card->dev,
@@ -83,16 +84,12 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,

 	/* write blank samples at head */
 	offset = 0;
-	size = BLANK_HEAD_SIZE;
-	if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
-		size *= 2;
+	size = BLANK_HEAD_SIZE << shift;
 	snd_emu10k1_synth_memset(emu, sp->block, offset, size, fill);
 	offset += size;

 	/* copy provided samples */
-	size = sp->v.size;
-	if (! (sp->v.mode_flags & SNDRV_SFNT_SAMPLE_8BITS))
-		size *= 2;
+	size = sp->v.size << shift;
 	if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor)) {
 		snd_emu10k1_synth_free(emu, sp->block);
 		sp->block = NULL;
--
2.42.0.419.g70bf8a5751


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 16/18] ALSA: emu10k1: improve cache behavior documentation
  2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
                   ` (14 preceding siblings ...)
  2024-04-01 10:07 ` [PATCH 15/18] ALSA: emu10k1: de-duplicate size calculations for 16-bit samples Oswald Buddenhagen
@ 2024-04-01 10:07 ` Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 17/18] ALSA: emu10k1: fix playback of short wavetable samples Oswald Buddenhagen
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 10:07 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Jaroslav Kysela, Arthur Marsh

Resulting from more reverse engineering in the course of debugging.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 include/sound/emu10k1.h | 28 ++++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)

diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 9e3bd4f81460..12c7dc760724 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -598,17 +598,25 @@ SUB_REG(PEFE, FILTERAMOUNT,	0x000000ff)	/* Filter envlope amount				*/
 // In stereo mode, the two channels' caches are concatenated into one,
 // and hold the interleaved frames.
 // The cache holds 64 frames, so the upper half is not used in 8-bit mode.
-// All registers mentioned below count in frames.
-// The cache is a ring buffer; CCR_READADDRESS operates modulo 64.
-// The cache is filled from (CCCA_CURRADDR - CCR_CACHEINVALIDSIZE)
-// into (CCR_READADDRESS - CCR_CACHEINVALIDSIZE).
+// All registers mentioned below count in frames. Shortcuts:
+//   CA = CCCA_CURRADDR, CRA = CCR_READADDRESS,
+//   CLA = CCR_CACHELOOPADDRHI:CLP_CACHELOOPADDR,
+//   CIS = CCR_CACHEINVALIDSIZE, LIS = CCR_LOOPINVALSIZE,
+//   CLF = CCR_CACHELOOPFLAG, LF = CCR_LOOPFLAG
+// The cache is a ring buffer; CRA operates modulo 64.
+// The cache is filled from (CA - CIS) into (CRA - CIS).
 // The engine has a fetch threshold of 32 bytes, so it tries to keep
-// CCR_CACHEINVALIDSIZE below 8 (16-bit stereo), 16 (16-bit mono,
-// 8-bit stereo), or 32 (8-bit mono). The actual transfers are pretty
-// unpredictable, especially if several voices are running.
-// Frames are consumed at CCR_READADDRESS, which is incremented afterwards,
-// along with CCCA_CURRADDR and CCR_CACHEINVALIDSIZE. This implies that the
-// actual playback position always lags CCCA_CURRADDR by exactly 64 frames.
+// CIS below 8 (16-bit stereo), 16 (16-bit mono, 8-bit stereo), or
+// 32 (8-bit mono). The actual transfers are pretty unpredictable,
+// especially if several voices are running.
+// Frames are consumed at CRA, which is incremented afterwards,
+// along with CA and CIS. This implies that the actual playback
+// position always lags CA by exactly 64 frames.
+// When CA reaches DSL_LOOPENDADDR, LF is set for one frame's time.
+// LF's rising edge causes the current values of CA and CIS to be
+// copied into CLA and LIS, resp., and CLF to be set.
+// If CLF is set, the first LIS of the CIS frames are instead
+// filled from (CLA - LIS), and CLF is subsequently reset.
 #define CD0			0x20		/* Cache data registers 0 .. 0x1f			*/

 #define PTB			0x40		/* Page table base register				*/
--
2.42.0.419.g70bf8a5751


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 17/18] ALSA: emu10k1: fix playback of short wavetable samples
  2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
                   ` (15 preceding siblings ...)
  2024-04-01 10:07 ` [PATCH 16/18] ALSA: emu10k1: improve cache behavior documentation Oswald Buddenhagen
@ 2024-04-01 10:07 ` Oswald Buddenhagen
  2024-04-01 10:07 ` [PATCH 18/18] ALSA: emux: simplify snd_sf_list.callback handling Oswald Buddenhagen
  2024-04-01 10:51 ` [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Takashi Iwai
  18 siblings, 0 replies; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 10:07 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Jaroslav Kysela, Arthur Marsh

As already anticipated in the linked commit, playback was broken for
very short samples. That's because we'd set the current position beyond
the end of the loop, so while the start would now be correct (due to the
cache lag), we'd run off the end of the sample and play garbage.

Fixing the playback position itself wouldn't be that hard (just modulo
it), but this wouldn't address pre-filling the cache with the right
data.

We could pre-fill the cache manually, but that's slow, requires
additional code for each sample width, and is made even more complex by
the driver's virtual address space having no contiguous mapping for the
CPU.

We could have the engine fill the cache piece-wise (which is really what
happens when playback is running), but that would also be complex, and
we'd need to wait for the engine to handle each piece, so it wouldn't be
that much faster than the manual fill.

For the case of requiring only one loop iteration prior to reaching the
cache size, one could leverage the engine's looping mechanism around
CCR_CACHELOOPFLAG, but this special case doesn't seem worth the
complexity.

So we just unroll the loop as far as necessary to be able to play back
the sample without any fiddling.

Pedantically, this would be incorrect for loop-until-release samples
with a low loop end which are released very quickly, but that would be
relatively harmless, is not a plausible use case in the first place, and
SoundFont sample mode 3 isn't actually implemented anyway (it's
conflated with mode 1, infinite looping).

Fixes: df335e9a8b (ALSA: emu10k1: fix synthesizer sample playback position and caching, 2023-05-18)
Link: https://bugzilla.kernel.org/show_bug.cgi?id=218625
Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 sound/pci/emu10k1/emu10k1_patch.c | 53 ++++++++++++++++++++++++++++---
 1 file changed, 48 insertions(+), 5 deletions(-)

diff --git a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c
index 699aa0fec97b..dbfa89435ac2 100644
--- a/sound/pci/emu10k1/emu10k1_patch.c
+++ b/sound/pci/emu10k1/emu10k1_patch.c
@@ -31,6 +31,7 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 	int shift;
 	int offset;
 	int truesize, size, blocksize;
+	int loop_start, loop_end, loop_size, data_end, unroll;
 	struct snd_emu10k1 *emu;

 	emu = rec->hw;
@@ -64,12 +65,35 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 		}
 	}

+	loop_start = sp->v.loopstart;
+	loop_end = sp->v.loopend;
+	loop_size = loop_end - loop_start;
+	if (!loop_size)
+		return -EINVAL;
+	data_end = sp->v.end;
+
 	/* recalculate offset */
 	sp->v.start += BLANK_HEAD_SIZE;
 	sp->v.end += BLANK_HEAD_SIZE;
 	sp->v.loopstart += BLANK_HEAD_SIZE;
 	sp->v.loopend += BLANK_HEAD_SIZE;

+	// Automatic pre-filling of the cache does not work in the presence
+	// of loops (*), and we don't want to fill it manually, as that is
+	// fiddly and slow. So we unroll the loop until the loop end is
+	// beyond the cache size.
+	// (*) Strictly speaking, a single iteration is supported (that's
+	// how it works when the playback engine runs), but handling this
+	// special case is not worth it.
+	unroll = 0;
+	while (sp->v.loopend < 64) {
+		truesize += loop_size;
+		sp->v.loopstart += loop_size;
+		sp->v.loopend += loop_size;
+		sp->v.end += loop_size;
+		unroll++;
+	}
+
 	/* try to allocate a memory block */
 	blocksize = truesize << shift;
 	sp->block = snd_emu10k1_synth_alloc(emu, blocksize);
@@ -89,19 +113,38 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp,
 	offset += size;

 	/* copy provided samples */
-	size = sp->v.size << shift;
-	if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor)) {
-		snd_emu10k1_synth_free(emu, sp->block);
-		sp->block = NULL;
-		return -EFAULT;
+	if (unroll && loop_end <= data_end) {
+		size = loop_end << shift;
+		if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor))
+			goto faulty;
+		offset += size;
+
+		data += loop_start << shift;
+		while (--unroll > 0) {
+			size = loop_size << shift;
+			if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor))
+				goto faulty;
+			offset += size;
+		}
+
+		size = (data_end - loop_start) << shift;
+	} else {
+		size = data_end << shift;
 	}
+	if (snd_emu10k1_synth_copy_from_user(emu, sp->block, offset, data, size, xor))
+		goto faulty;
 	offset += size;

 	/* clear rest of samples (if any) */
 	if (offset < blocksize)
 		snd_emu10k1_synth_memset(emu, sp->block, offset, blocksize - offset, fill);

 	return 0;
+
+faulty:
+	snd_emu10k1_synth_free(emu, sp->block);
+	sp->block = NULL;
+	return -EFAULT;
 }

 /*
--
2.42.0.419.g70bf8a5751


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* [PATCH 18/18] ALSA: emux: simplify snd_sf_list.callback handling
  2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
                   ` (16 preceding siblings ...)
  2024-04-01 10:07 ` [PATCH 17/18] ALSA: emu10k1: fix playback of short wavetable samples Oswald Buddenhagen
@ 2024-04-01 10:07 ` Oswald Buddenhagen
  2024-04-01 10:51 ` [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Takashi Iwai
  18 siblings, 0 replies; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 10:07 UTC (permalink / raw)
  To: alsa-devel; +Cc: Takashi Iwai, Jaroslav Kysela, Arthur Marsh

Both drivers provide both sample_new and sample_free, and it makes no
sense to pretend that they could not. In fact, load_data() would already
crash if sample_new was null. So remove the remaining null checks.

Contrary to that, the emu10k1 driver actually has a null sample_reset,
though I'm not convinced that this inconsistency is justified.

Signed-off-by: Oswald Buddenhagen <oswald.buddenhagen@gmx.de>
---
 sound/synth/emux/emux.c      |  6 ++----
 sound/synth/emux/soundfont.c | 12 +++++-------
 2 files changed, 7 insertions(+), 11 deletions(-)

diff --git a/sound/synth/emux/emux.c b/sound/synth/emux/emux.c
index a82af9374852..01444fc960d0 100644
--- a/sound/synth/emux/emux.c
+++ b/sound/synth/emux/emux.c
@@ -94,10 +94,8 @@ int snd_emux_register(struct snd_emux *emu, struct snd_card *card, int index, ch
 	/* create soundfont list */
 	memset(&sf_cb, 0, sizeof(sf_cb));
 	sf_cb.private_data = emu;
-	if (emu->ops.sample_new)
-		sf_cb.sample_new = sf_sample_new;
-	if (emu->ops.sample_free)
-		sf_cb.sample_free = sf_sample_free;
+	sf_cb.sample_new = sf_sample_new;
+	sf_cb.sample_free = sf_sample_free;
 	if (emu->ops.sample_reset)
 		sf_cb.sample_reset = sf_sample_reset;
 	emu->sflist = snd_sf_new(&sf_cb, emu->memhdr);
diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c
index 4edc693da8e7..2373ed580bf8 100644
--- a/sound/synth/emux/soundfont.c
+++ b/sound/synth/emux/soundfont.c
@@ -1051,7 +1051,7 @@ load_guspatch(struct snd_sf_list *sflist, const char __user *data, long count)
 	/*
 	 * load wave data
 	 */
-	if (smp->v.size > 0 && sflist->callback.sample_new) {
+	if (smp->v.size > 0) {
 		rc = sflist->callback.sample_new
 			(sflist->callback.private_data, smp, sflist->memhdr,
 			 data, count);
@@ -1416,9 +1416,8 @@ snd_sf_clear(struct snd_sf_list *sflist)
 		}
 		for (sp = sf->samples; sp; sp = nextsp) {
 			nextsp = sp->next;
-			if (sflist->callback.sample_free)
-				sflist->callback.sample_free(sflist->callback.private_data,
-							     sp, sflist->memhdr);
+			sflist->callback.sample_free(sflist->callback.private_data,
+						     sp, sflist->memhdr);
 			kfree(sp);
 		}
 		kfree(sf);
@@ -1520,9 +1519,8 @@ snd_soundfont_remove_unlocked(struct snd_sf_list *sflist)
 			nextsp = sp->next;
 			sf->samples = nextsp;
 			sflist->mem_used -= sp->v.truesize;
-			if (sflist->callback.sample_free)
-				sflist->callback.sample_free(sflist->callback.private_data,
-							     sp, sflist->memhdr);
+			sflist->callback.sample_free(sflist->callback.private_data,
+						     sp, sflist->memhdr);
 			kfree(sp);
 		}
 	}
--
2.42.0.419.g70bf8a5751


^ permalink raw reply related	[flat|nested] 22+ messages in thread

* Re: [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback
  2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
                   ` (17 preceding siblings ...)
  2024-04-01 10:07 ` [PATCH 18/18] ALSA: emux: simplify snd_sf_list.callback handling Oswald Buddenhagen
@ 2024-04-01 10:51 ` Takashi Iwai
  2024-04-01 11:18   ` Oswald Buddenhagen
  18 siblings, 1 reply; 22+ messages in thread
From: Takashi Iwai @ 2024-04-01 10:51 UTC (permalink / raw)
  To: Oswald Buddenhagen; +Cc: alsa-devel, Jaroslav Kysela, Arthur Marsh

On Mon, 01 Apr 2024 12:07:24 +0200,
Oswald Buddenhagen wrote:
> 
> this fixes the regression i introduced (though arguably, i just made it broken
> in a different way), and then some more.
> 
> Oswald Buddenhagen (18):
>   ALSA: emux: fix /proc teardown at module unload
>   ALSA: emux: prune unused parameter from snd_soundfont_load_guspatch()
>   ALSA: emux: fix validation of snd_emux.num_ports
>   ALSA: emux: fix init of patch_info.truesize in load_data()
>   ALSA: emu10k1: prune vestiges of
>     SNDRV_SFNT_SAMPLE_{BIDIR,REVERSE}_LOOP support
>   ALSA: emux: centralize & improve patch info validation
>   ALSA: emux: improve patch ioctl data validation
>   ALSA: emu10k1: move patch loader assertions into low-level functions
>   ALSA: emu10k1: fix sample signedness issues in wavetable loader
>   ALSA: emu10k1: fix playback of 8-bit wavetable samples
>   ALSA: emu10k1: make wavetable sample playback start position exact
>   ALSA: emu10k1: shrink blank space in front of wavetable samples
>   ALSA: emu10k1: merge conditions in patch loader
>   ALSA: emu10k1: fix wavetable offset recalculation
>   ALSA: emu10k1: de-duplicate size calculations for 16-bit samples
>   ALSA: emu10k1: improve cache behavior documentation
>   ALSA: emu10k1: fix playback of short wavetable samples
>   ALSA: emux: simplify snd_sf_list.callback handling

Could you give Fixes tag in each commit if it's a regression fix for
the  corresponding commit?


thanks,

Takashi

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback
  2024-04-01 10:51 ` [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Takashi Iwai
@ 2024-04-01 11:18   ` Oswald Buddenhagen
  2024-04-01 11:44     ` Takashi Iwai
  0 siblings, 1 reply; 22+ messages in thread
From: Oswald Buddenhagen @ 2024-04-01 11:18 UTC (permalink / raw)
  To: Takashi Iwai; +Cc: alsa-devel, Jaroslav Kysela, Arthur Marsh

On Mon, Apr 01, 2024 at 12:51:32PM +0200, Takashi Iwai wrote:
>Could you give Fixes tag in each commit if it's a regression fix for
>the  corresponding commit?
>
i did. you'll see it when the later patches arrive (minor hiccup with
mail delivery on my end ...).

of course this won't help a lot with picking to stable, because the fix
actually depends on several of the prior patches. i can re-arrange the
series to minimize the hard dependency chain, but it will still be ~10
patches.

an alternative approach would be just reverting the offending patch and
re-fixing it as part of the subsequent series. the revert would be
easily pickable, but that merely replaces the current problem with the
(admittedly less audible) previous problem. your choice.

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback
  2024-04-01 11:18   ` Oswald Buddenhagen
@ 2024-04-01 11:44     ` Takashi Iwai
  0 siblings, 0 replies; 22+ messages in thread
From: Takashi Iwai @ 2024-04-01 11:44 UTC (permalink / raw)
  To: Oswald Buddenhagen; +Cc: alsa-devel, Jaroslav Kysela, Arthur Marsh

On Mon, 01 Apr 2024 13:18:36 +0200,
Oswald Buddenhagen wrote:
> 
> On Mon, Apr 01, 2024 at 12:51:32PM +0200, Takashi Iwai wrote:
> > Could you give Fixes tag in each commit if it's a regression fix for
> > the  corresponding commit?
> > 
> i did. you'll see it when the later patches arrive (minor hiccup with
> mail delivery on my end ...).
> 
> of course this won't help a lot with picking to stable, because the fix
> actually depends on several of the prior patches. i can re-arrange the
> series to minimize the hard dependency chain, but it will still be ~10
> patches.
>
> an alternative approach would be just reverting the offending patch and
> re-fixing it as part of the subsequent series. the revert would be
> easily pickable, but that merely replaces the current problem with the
> (admittedly less audible) previous problem. your choice.

Judging from the amount of patches, I prefer a quicker "fix" for the
known regression, so a revert-and-rewrite sounds more like a
reasonable approach.  Care to resubmit with that?


thanks,

Takashi

^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2024-04-01 12:24 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-04-01 10:07 [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Oswald Buddenhagen
2024-04-01 10:07 ` [PATCH 01/18] ALSA: emux: fix /proc teardown at module unload Oswald Buddenhagen
2024-04-01 10:07 ` [PATCH 02/18] ALSA: emux: prune unused parameter from snd_soundfont_load_guspatch() Oswald Buddenhagen
2024-04-01 10:07 ` [PATCH 03/18] ALSA: emux: fix validation of snd_emux.num_ports Oswald Buddenhagen
2024-04-01 10:07 ` [PATCH 04/18] ALSA: emux: fix init of patch_info.truesize in load_data() Oswald Buddenhagen
2024-04-01 10:07 ` [PATCH 05/18] ALSA: emu10k1: prune vestiges of SNDRV_SFNT_SAMPLE_{BIDIR,REVERSE}_LOOP support Oswald Buddenhagen
2024-04-01 10:07 ` [PATCH 06/18] ALSA: emux: centralize & improve patch info validation Oswald Buddenhagen
2024-04-01 10:07 ` [PATCH 07/18] ALSA: emux: improve patch ioctl data validation Oswald Buddenhagen
2024-04-01 10:07 ` [PATCH 08/18] ALSA: emu10k1: move patch loader assertions into low-level functions Oswald Buddenhagen
2024-04-01 10:07 ` [PATCH 09/18] ALSA: emu10k1: fix sample signedness issues in wavetable loader Oswald Buddenhagen
2024-04-01 10:07 ` [PATCH 10/18] ALSA: emu10k1: fix playback of 8-bit wavetable samples Oswald Buddenhagen
2024-04-01 10:07 ` [PATCH 11/18] ALSA: emu10k1: make wavetable sample playback start position exact Oswald Buddenhagen
2024-04-01 10:07 ` [PATCH 12/18] ALSA: emu10k1: shrink blank space in front of wavetable samples Oswald Buddenhagen
2024-04-01 10:07 ` [PATCH 13/18] ALSA: emu10k1: merge conditions in patch loader Oswald Buddenhagen
2024-04-01 10:07 ` [PATCH 14/18] ALSA: emu10k1: fix wavetable offset recalculation Oswald Buddenhagen
2024-04-01 10:07 ` [PATCH 15/18] ALSA: emu10k1: de-duplicate size calculations for 16-bit samples Oswald Buddenhagen
2024-04-01 10:07 ` [PATCH 16/18] ALSA: emu10k1: improve cache behavior documentation Oswald Buddenhagen
2024-04-01 10:07 ` [PATCH 17/18] ALSA: emu10k1: fix playback of short wavetable samples Oswald Buddenhagen
2024-04-01 10:07 ` [PATCH 18/18] ALSA: emux: simplify snd_sf_list.callback handling Oswald Buddenhagen
2024-04-01 10:51 ` [PATCH 00/18] ALSA: emu10k1 & emux: fixes related to wavetable playback Takashi Iwai
2024-04-01 11:18   ` Oswald Buddenhagen
2024-04-01 11:44     ` Takashi Iwai

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox