All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2] alsaloop: added option prateshift for PLAYSHIFT ctl elem used in PLAYSHIFT
@ 2021-10-05 19:49 Pavel Hofman
  2021-10-13  7:01 ` Jaroslav Kysela
  0 siblings, 1 reply; 2+ messages in thread
From: Pavel Hofman @ 2021-10-05 19:49 UTC (permalink / raw)
  To: alsa-devel; +Cc: Pavel Hofman

If snd-aloop device is on playback side, the required sync mode is
PLAYSHIFT. That means Loopback ctl elem "PCM Rate Shift 100000" of the
corresponding capture side of the Loopback pipe must be controlled (by
pitch reciprocal).

ASCII name of the playback rate shift ctl elem is specified with newly
added option -x/--prateshift, e.g.:
-P hw:Loopback,0 -S playshift \
-x iface=PCM,name='PCM Rate Shift 100000',device=1

Signed-off-by: Pavel Hofman <pavel.hofman@ivitera.com>
---
 alsaloop/alsaloop.1 | 11 ++++--
 alsaloop/alsaloop.c | 11 +++++-
 alsaloop/alsaloop.h |  1 +
 alsaloop/pcmjob.c   | 83 ++++++++++++++++++++++++++++++++++-----------
 4 files changed, 83 insertions(+), 23 deletions(-)

diff --git a/alsaloop/alsaloop.1 b/alsaloop/alsaloop.1
index 6bacfd5..006494d 100644
--- a/alsaloop/alsaloop.1
+++ b/alsaloop/alsaloop.1
@@ -57,6 +57,11 @@ Use given CTL device for playback.
 
 Use given CTL device for capture.
 
+.TP
+\fI\-x <ctl_ascii_name>\fP | \fI\-\-prateshift=<ctl_ascii_name>\fP
+
+Specify ctl ascii name for playshift sync mode (see the Examples section).
+
 .TP
 \fI\-l <latency>\fP | \fI\-\-latency=<frames>\fP
 
@@ -195,10 +200,12 @@ Verbose xrun profiling.
 Set process wake timeout.
 
 .SH EXAMPLES
-
-.TP
+.nf
 \fBalsaloop \-C hw:0,0 \-P hw:1,0 \-t 50000\fR
 
+\fBalsaloop \-C hw:soundcard,0 \-P hw:Loopback,0 \-t 50000 \-S playshift \\
+\-x iface=PCM,name='PCM Rate Shift 100000',device=1\fR
+.ne
 .SH BUGS
 None known.
 .SH AUTHOR
diff --git a/alsaloop/alsaloop.c b/alsaloop/alsaloop.c
index 06ffadf..4192712 100644
--- a/alsaloop/alsaloop.c
+++ b/alsaloop/alsaloop.c
@@ -175,6 +175,7 @@ void help(void)
 "-C,--cdevice   capture device\n"
 "-X,--pctl      playback ctl device\n"
 "-Y,--cctl      capture ctl device\n"
+"-x,--prateshift playback 'PCM Rate Shift 100000' ascii ctl name\n"
 "-l,--latency   requested latency in frames\n"
 "-t,--tlatency  requested latency in usec (1/1000000sec)\n"
 "-f,--format    sample format\n"
@@ -362,6 +363,7 @@ static int parse_config(int argc, char *argv[], snd_output_t *output,
 		{"cdevice", 1, NULL, 'C'},
 		{"pctl", 1, NULL, 'X'},
 		{"cctl", 1, NULL, 'Y'},
+		{"prateshift", 1, NULL, 'x'},
 		{"latency", 1, NULL, 'l'},
 		{"tlatency", 1, NULL, 't'},
 		{"format", 1, NULL, 'f'},
@@ -391,6 +393,7 @@ static int parse_config(int argc, char *argv[], snd_output_t *output,
 	char *arg_cdevice = NULL;
 	char *arg_pctl = NULL;
 	char *arg_cctl = NULL;
+	char *arg_prateshift = NULL;
 	unsigned int arg_latency_req = 0;
 	unsigned int arg_latency_reqtime = 10000;
 	snd_pcm_format_t arg_format = SND_PCM_FORMAT_S16_LE;
@@ -420,7 +423,7 @@ static int parse_config(int argc, char *argv[], snd_output_t *output,
 	while (1) {
 		int c;
 		if ((c = getopt_long(argc, argv,
-				"hdg:P:C:X:Y:l:t:F:f:c:r:s:benvA:S:a:m:T:O:w:UW:z",
+				"hdg:P:C:X:Y:x:l:t:F:f:c:r:s:benvA:S:a:m:T:O:w:UW:z",
 				long_option, NULL)) < 0)
 			break;
 		switch (c) {
@@ -446,6 +449,9 @@ static int parse_config(int argc, char *argv[], snd_output_t *output,
 		case 'Y':
 			arg_cctl = strdup(optarg);
 			break;
+		case 'x':
+			arg_prateshift = strdup(optarg);
+			break;
 		case 'l':
 			err = atoi(optarg);
 			arg_latency_req = err >= 4 ? err : 4;
@@ -627,6 +633,9 @@ static int parse_config(int argc, char *argv[], snd_output_t *output,
 			logit(LOG_CRIT, "Unable to add ossmixer controls.\n");
 			exit(EXIT_FAILURE);
 		}
+		if (arg_prateshift)
+			play->prateshift_name = arg_prateshift;
+
 #ifdef USE_SAMPLERATE
 		loop->src_enable = arg_samplerate > 0;
 		if (loop->src_enable)
diff --git a/alsaloop/alsaloop.h b/alsaloop/alsaloop.h
index 1dbcefe..7a98ef3 100644
--- a/alsaloop/alsaloop.h
+++ b/alsaloop/alsaloop.h
@@ -127,6 +127,7 @@ struct loopback_handle {
 	snd_ctl_elem_value_t *ctl_format;
 	snd_ctl_elem_value_t *ctl_rate;
 	snd_ctl_elem_value_t *ctl_channels;
+	char *prateshift_name; /* ascii name for the playback rate shift ctl elem */
 };
 
 struct loopback {
diff --git a/alsaloop/pcmjob.c b/alsaloop/pcmjob.c
index 845ab82..8658fa6 100644
--- a/alsaloop/pcmjob.c
+++ b/alsaloop/pcmjob.c
@@ -1101,7 +1101,8 @@ void update_pitch(struct loopback *loop)
 #endif
 	}
 	else if (loop->sync == SYNC_TYPE_PLAYRATESHIFT) {
-		set_rate_shift(loop->play, pitch);
+		// pitch is capture-based, playback side requires reciprocal
+		set_rate_shift(loop->play, 1 / pitch);
 #ifdef USE_SAMPLERATE
 		if (loop->use_samplerate) {
 			loop->src_data.src_ratio = 
@@ -1172,44 +1173,86 @@ static int get_channels(struct loopback_handle *lhandle)
 	return snd_ctl_elem_value_get_integer(lhandle->ctl_channels, 0);
 }
 
-static void openctl_elem(struct loopback_handle *lhandle,
-			 int device, int subdevice,
-			 const char *name,
-			 snd_ctl_elem_value_t **elem)
+static int openctl_elem_id(struct loopback_handle *lhandle, snd_ctl_elem_id_t *id,
+		snd_ctl_elem_value_t **elem)
 {
 	int err;
 
 	if (snd_ctl_elem_value_malloc(elem) < 0) {
 		*elem = NULL;
+		snd_ctl_elem_id_free(id);
+ 		return -ENOMEM;
+ 	}
+	snd_ctl_elem_value_set_id(*elem, id);
+	snd_ctl_elem_value_set_interface(*elem, SND_CTL_ELEM_IFACE_PCM);
+	err = snd_ctl_elem_read(lhandle->ctl, *elem);
+	if (err < 0) {
+		snd_ctl_elem_id_free(id);
+		snd_ctl_elem_value_free(*elem);
+		*elem = NULL;
+		return err;
 	} else {
-		snd_ctl_elem_value_set_interface(*elem,
-						 SND_CTL_ELEM_IFACE_PCM);
-		snd_ctl_elem_value_set_device(*elem, device);
-		snd_ctl_elem_value_set_subdevice(*elem, subdevice);
-		snd_ctl_elem_value_set_name(*elem, name);
-		err = snd_ctl_elem_read(lhandle->ctl, *elem);
-		if (err < 0) {
-			snd_ctl_elem_value_free(*elem);
-			*elem = NULL;
-		} else {
-			if (verbose)
-				snd_output_printf(lhandle->loopback->output,
-						"Opened PCM element %s of %s, device %d, subdevice %d\n",
-						name, snd_ctl_name(lhandle->ctl), device, subdevice);
-		}
+		snd_output_printf(lhandle->loopback->output,
+				"Opened PCM element %s of %s, device %d, subdevice %d\n",
+				snd_ctl_elem_id_get_name(id), snd_ctl_name(lhandle->ctl),
+				snd_ctl_elem_id_get_device(id),
+				snd_ctl_elem_id_get_subdevice(id));
+		return 0;
 	}
 }
 
+static int openctl_elem(struct loopback_handle *lhandle,
+			 int device, int subdevice,
+			 const char *name,
+			 snd_ctl_elem_value_t **elem)
+{
+	snd_ctl_elem_id_t *id;
+
+	if (snd_ctl_elem_id_malloc(&id))
+		return -ENOMEM;
+	snd_ctl_elem_id_set_device(id, device);
+	snd_ctl_elem_id_set_subdevice(id, subdevice);
+	snd_ctl_elem_id_set_name(id, name);
+	return openctl_elem_id(lhandle, id, elem);
+}
+
+static int openctl_elem_ascii(struct loopback_handle *lhandle, char *ascii_name,
+		snd_ctl_elem_value_t **elem)
+{
+	snd_ctl_elem_id_t *id;
+
+	if (snd_ctl_elem_id_malloc(&id)) {
+		return -ENOMEM;
+	}
+	if (snd_ctl_ascii_elem_id_parse(id, ascii_name)) {
+		snd_ctl_elem_id_free(id);
+		fprintf(stderr, "Wrong control identifier: %s\n", ascii_name);
+		return -EINVAL;
+	}
+	return openctl_elem_id(lhandle, id, elem);
+}
+
 static int openctl(struct loopback_handle *lhandle, int device, int subdevice)
 {
 	int err;
 
 	lhandle->ctl_rate_shift = NULL;
 	if (lhandle->loopback->play == lhandle) {
+		// play only
+		if (lhandle->prateshift_name) {
+			err = openctl_elem_ascii(lhandle, lhandle->prateshift_name,
+					&lhandle->ctl_rate_shift);
+			if (err < 0) {
+				logit(LOG_CRIT, "Unable to open playback PCM Rate Shift elem '%s'.\n",
+						lhandle->prateshift_name);
+				exit(EXIT_FAILURE);
+			}
+		}
 		if (lhandle->loopback->controls)
 			goto __events;
 		return 0;
 	}
+	// capture only
 	openctl_elem(lhandle, device, subdevice, "PCM Notify",
 			&lhandle->ctl_notify);
 	openctl_elem(lhandle, device, subdevice, "PCM Rate Shift 100000",
-- 
2.25.1


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

* Re: [PATCH v2] alsaloop: added option prateshift for PLAYSHIFT ctl elem used in PLAYSHIFT
  2021-10-05 19:49 [PATCH v2] alsaloop: added option prateshift for PLAYSHIFT ctl elem used in PLAYSHIFT Pavel Hofman
@ 2021-10-13  7:01 ` Jaroslav Kysela
  0 siblings, 0 replies; 2+ messages in thread
From: Jaroslav Kysela @ 2021-10-13  7:01 UTC (permalink / raw)
  To: Pavel Hofman, alsa-devel

On 05. 10. 21 21:49, Pavel Hofman wrote:

> -static void openctl_elem(struct loopback_handle *lhandle,
> -			 int device, int subdevice,
> -			 const char *name,
> -			 snd_ctl_elem_value_t **elem)
> +static int openctl_elem_id(struct loopback_handle *lhandle, snd_ctl_elem_id_t *id,
> +		snd_ctl_elem_value_t **elem)
>   {
>   	int err;
>   
>   	if (snd_ctl_elem_value_malloc(elem) < 0) {
>   		*elem = NULL;
> +		snd_ctl_elem_id_free(id);
> + 		return -ENOMEM;
> + 	}
> +	snd_ctl_elem_value_set_id(*elem, id);
> +	snd_ctl_elem_value_set_interface(*elem, SND_CTL_ELEM_IFACE_PCM);
> +	err = snd_ctl_elem_read(lhandle->ctl, *elem);
> +	if (err < 0) {
> +		snd_ctl_elem_id_free(id);

Move the id allocation management to the caller.

> +		snd_ctl_elem_value_free(*elem);
> +		*elem = NULL;
> +		return err;
>   	} else {
> -		snd_ctl_elem_value_set_interface(*elem,
> -						 SND_CTL_ELEM_IFACE_PCM);
> -		snd_ctl_elem_value_set_device(*elem, device);
> -		snd_ctl_elem_value_set_subdevice(*elem, subdevice);
> -		snd_ctl_elem_value_set_name(*elem, name);
> -		err = snd_ctl_elem_read(lhandle->ctl, *elem);
> -		if (err < 0) {
> -			snd_ctl_elem_value_free(*elem);
> -			*elem = NULL;
> -		} else {
> -			if (verbose)
> -				snd_output_printf(lhandle->loopback->output,
> -						"Opened PCM element %s of %s, device %d, subdevice %d\n",
> -						name, snd_ctl_name(lhandle->ctl), device, subdevice);
> -		}
> +		snd_output_printf(lhandle->loopback->output,
> +				"Opened PCM element %s of %s, device %d, subdevice %d\n",
> +				snd_ctl_elem_id_get_name(id), snd_ctl_name(lhandle->ctl),
> +				snd_ctl_elem_id_get_device(id),
> +				snd_ctl_elem_id_get_subdevice(id));
> +		return 0;
>   	}
>   }
>   
> +static int openctl_elem(struct loopback_handle *lhandle,
> +			 int device, int subdevice,
> +			 const char *name,
> +			 snd_ctl_elem_value_t **elem)
> +{
> +	snd_ctl_elem_id_t *id;
> +
> +	if (snd_ctl_elem_id_malloc(&id))
> +		return -ENOMEM;
> +	snd_ctl_elem_id_set_device(id, device);
> +	snd_ctl_elem_id_set_subdevice(id, subdevice);
> +	snd_ctl_elem_id_set_name(id, name);
> +	return openctl_elem_id(lhandle, id, elem);

Missing snd_ctl_elem_id_free(id). Eventually, the id may be allocated using 
snd_ctl_elem_id_alloca().

> +}
> +
> +static int openctl_elem_ascii(struct loopback_handle *lhandle, char *ascii_name,
> +		snd_ctl_elem_value_t **elem)
> +{
> +	snd_ctl_elem_id_t *id;
> +
> +	if (snd_ctl_elem_id_malloc(&id)) {
> +		return -ENOMEM;
> +	}
> +	if (snd_ctl_ascii_elem_id_parse(id, ascii_name)) {
> +		snd_ctl_elem_id_free(id);
> +		fprintf(stderr, "Wrong control identifier: %s\n", ascii_name);
> +		return -EINVAL;
> +	}
> +	return openctl_elem_id(lhandle, id, elem);

Missing snd_ctl_elem_id_free(id). Eventually, the id may be allocated using 
snd_ctl_elem_id_alloca().

						Jaroslav

-- 
Jaroslav Kysela <perex@perex.cz>
Linux Sound Maintainer; ALSA Project; Red Hat, Inc.

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

end of thread, other threads:[~2021-10-13  7:02 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-10-05 19:49 [PATCH v2] alsaloop: added option prateshift for PLAYSHIFT ctl elem used in PLAYSHIFT Pavel Hofman
2021-10-13  7:01 ` Jaroslav Kysela

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.