All of lore.kernel.org
 help / color / mirror / Atom feed
* PCM Plugin Channel question
@ 2014-07-01 22:59 Brandon Yates
  2014-07-02  3:45 ` Alexander E. Patrakov
  0 siblings, 1 reply; 5+ messages in thread
From: Brandon Yates @ 2014-07-01 22:59 UTC (permalink / raw)
  To: alsa-devel


Hello, I have developed a pcm ext plugin that applies some processing to the audio stream in the transfer callback.

My plugin works for a mono (1 channel) stream. I'd now like to expand it to support stereo data in the form of 2 channels interleaved.  I can't find much information on how this works.  I have a couple questions that I'd greatly appreciate if anyone could help with.

1) Is there any way in the 'SND_PCM_PLUGIN_DEFINE_FUNC' function that I can determine if the user application has opened the stream with 1 channel vs 2 channel? 

2) I assume in the case of two channels my transfer function would need to: a)deinterleave the data from source so my processing routine can access it in a linear buffer and b) reinterleave the data before I copy it to destination.   Is this correct? Is there more to it or things I am overlooking?

3) For IO-plugin I see there is a `SND_PCM_IOPLUG_HW_ACCESS` value I could use to restrict the stream type to `SND_PCM_ACCESS_RW_INTERLEAVED`.  Does there exist a similar function for External PCM Plugin?

4)Is there some fundamental design idea here I am not grasping?

Thanks much!

Brandon

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

* Re: PCM Plugin Channel question
  2014-07-01 22:59 PCM Plugin Channel question Brandon Yates
@ 2014-07-02  3:45 ` Alexander E. Patrakov
  2014-07-02 13:25   ` Brandon Yates
  0 siblings, 1 reply; 5+ messages in thread
From: Alexander E. Patrakov @ 2014-07-02  3:45 UTC (permalink / raw)
  To: Brandon Yates; +Cc: ALSA Development Mailing List

02.07.2014 04:59, Brandon Yates wrote:

> Hello, I have developed a pcm ext plugin that applies some processing
> to the audio stream in the transfer callback.

Yes, this is how extplug is supposed to be used.

> My plugin works for a mono (1 channel) stream. I'd now like to expand
> it to support stereo data in the form of 2 channels interleaved.  I
> can't find much information on how this works.  I have a couple
> questions that I'd greatly appreciate if anyone could help with.
>
> 1) Is there any way in the 'SND_PCM_PLUGIN_DEFINE_FUNC' function that
> I can determine if the user application has opened the stream with 1
> channel vs 2 channel?

There certainly is such information, but not directly in 
SND_PCM_PLUGIN_DEFINE_FUNC. The code should be placed in the init 
callback. The argument of that callback has a parameter of type 
snd_pcm_extplug_t*, and that structure has a "channels" field.

You can use https://gitorious.org/dtsenc/dtsenc/source/alsaplugin.c as a 
model (but it needs to be updated to support channel maps). All actual 
processing is done in the dcaenc_convert_s32 function which is called by 
the transfer callback.

>
> 2) I assume in the case of two channels my transfer function would
> need to: a)deinterleave the data from source so my processing routine
> can access it in a linear buffer and b) reinterleave the data before
> I copy it to destination.   Is this correct? Is there more to it or
> things I am overlooking?

This is more-or-less correct. Just be sure to use the areas-related 
parameters to do deinterleaving correctly, because they can describe not 
only a simple interleaved format.

> 3) For IO-plugin I see there is a `SND_PCM_IOPLUG_HW_ACCESS` value I
> could use to restrict the stream type to
> `SND_PCM_ACCESS_RW_INTERLEAVED`.  Does there exist a similar function
> for External PCM Plugin?

You just don't have to apply this restriction.

SND_PCM_ACCESS_MMAP_INTERLEAVED will also work without any effort on 
your side, due to your transfer function being called on 
snd_pcm_mmap_commit. And, if you use the areas-related parameters 
correctly, the plugin will also work with planar or complex layouts.

<troll>
But... why are you writing an ALSA plugin? This means that your code 
will not be usable with PulseAudio out of the box, because PulseAudio 
can talk to custom PCMs only through module-alsa-sink, which means there 
will be no jack detection and similar card-related features.

Both ALSA and PulseAudio can wrap LADSPA plugins. Write that. And 
PulseAudio knows how to use N copies of a mono plugin to process an 
N-channel stream, so you don't have to deal with that yourself.
</troll>

-- 
Alexander E. Patrakov

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

* Re: PCM Plugin Channel question
  2014-07-02  3:45 ` Alexander E. Patrakov
@ 2014-07-02 13:25   ` Brandon Yates
  2014-07-02 13:51     ` Alexander E. Patrakov
  0 siblings, 1 reply; 5+ messages in thread
From: Brandon Yates @ 2014-07-02 13:25 UTC (permalink / raw)
  To: Alexander E. Patrakov; +Cc: ALSA Development Mailing List

Alex -  thanks. That was helpful. One follow up question.

> if you use the areas-related parameters correctly, the plugin will
also work with planar or complex layouts.


I am not sure if I'm using snd_pcm_channel_area_t correctly. I don't
really understand all the fields.  For 1 channel setup I stole the
following function from the speex plugin 

static inline void *area_addr(const snd_pcm_channel_area_t *area,
			      snd_pcm_uframes_t offset)
{
	unsigned int bitofs = area->first + area->step * offset;
	return (char *) area->addr + bitofs / 8;
}

This works for 1 channel but I don't understand how I would use area for
interleaved data.  My thoughts are just take the returned address from
area_addr then use a for loop separating out odd and even shorts.   Is
there a better way?



Will consider your points about PulseAudio too.  This plugin is
targeting embedded arm-linux systems so I'm not totally sure if Pulse
would even be used.



-----Original Message-----
From: Alexander E. Patrakov [mailto:patrakov@gmail.com] 
Sent: Tuesday, July 01, 2014 11:45 PM
To: Brandon Yates
Cc: ALSA Development Mailing List
Subject: Re: [alsa-devel] PCM Plugin Channel question

02.07.2014 04:59, Brandon Yates wrote:

> Hello, I have developed a pcm ext plugin that applies some processing 
> to the audio stream in the transfer callback.

Yes, this is how extplug is supposed to be used.

> My plugin works for a mono (1 channel) stream. I'd now like to expand 
> it to support stereo data in the form of 2 channels interleaved.  I 
> can't find much information on how this works.  I have a couple 
> questions that I'd greatly appreciate if anyone could help with.
>
> 1) Is there any way in the 'SND_PCM_PLUGIN_DEFINE_FUNC' function that 
> I can determine if the user application has opened the stream with 1 
> channel vs 2 channel?

There certainly is such information, but not directly in
SND_PCM_PLUGIN_DEFINE_FUNC. The code should be placed in the init
callback. The argument of that callback has a parameter of type
snd_pcm_extplug_t*, and that structure has a "channels" field.

You can use https://gitorious.org/dtsenc/dtsenc/source/alsaplugin.c as a
model (but it needs to be updated to support channel maps). All actual
processing is done in the dcaenc_convert_s32 function which is called by
the transfer callback.

>
> 2) I assume in the case of two channels my transfer function would 
> need to: a)deinterleave the data from source so my processing routine 
> can access it in a linear buffer and b) reinterleave the data before
> I copy it to destination.   Is this correct? Is there more to it or
> things I am overlooking?

This is more-or-less correct. Just be sure to use the areas-related
parameters to do deinterleaving correctly, because they can describe not
only a simple interleaved format.

> 3) For IO-plugin I see there is a `SND_PCM_IOPLUG_HW_ACCESS` value I 
> could use to restrict the stream type to 
> `SND_PCM_ACCESS_RW_INTERLEAVED`.  Does there exist a similar function 
> for External PCM Plugin?

You just don't have to apply this restriction.

SND_PCM_ACCESS_MMAP_INTERLEAVED will also work without any effort on
your side, due to your transfer function being called on
snd_pcm_mmap_commit. And, if you use the areas-related parameters
correctly, the plugin will also work with planar or complex layouts.

<troll>
But... why are you writing an ALSA plugin? This means that your code
will not be usable with PulseAudio out of the box, because PulseAudio
can talk to custom PCMs only through module-alsa-sink, which means there
will be no jack detection and similar card-related features.

Both ALSA and PulseAudio can wrap LADSPA plugins. Write that. And
PulseAudio knows how to use N copies of a mono plugin to process an
N-channel stream, so you don't have to deal with that yourself.
</troll>

--
Alexander E. Patrakov

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

* Re: PCM Plugin Channel question
  2014-07-02 13:25   ` Brandon Yates
@ 2014-07-02 13:51     ` Alexander E. Patrakov
  2014-07-02 13:57       ` Brandon Yates
  0 siblings, 1 reply; 5+ messages in thread
From: Alexander E. Patrakov @ 2014-07-02 13:51 UTC (permalink / raw)
  To: Brandon Yates; +Cc: alsa-devel

02.07.2014 19:25, Brandon Yates пишет:
> Alex -  thanks. That was helpful. One follow up question.
>
>> if you use the areas-related parameters correctly, the plugin will
> also work with planar or complex layouts.
>
>
> I am not sure if I'm using snd_pcm_channel_area_t correctly. I don't
> really understand all the fields.  For 1 channel setup I stole the
> following function from the speex plugin
>
> static inline void *area_addr(const snd_pcm_channel_area_t *area,
> 			      snd_pcm_uframes_t offset)
> {
> 	unsigned int bitofs = area->first + area->step * offset;
> 	return (char *) area->addr + bitofs / 8;
> }
>
> This works for 1 channel but I don't understand how I would use area for
> interleaved data.  My thoughts are just take the returned address from
> area_addr then use a for loop separating out odd and even shorts.   Is
> there a better way?

For stereo data, the key thought that you are missing is that there will 
be in fact _two_ areas for stereo data: area[0] and area[1]. Similarly 
for 4-channel data: 4 areas. One area per channel.

So, assuming interleaved stereo S16 audio, you will get the following 
two areas:

In area[0], addr points to the 0th left sample, first == 0, step == 32.
In area[1], either addr points to the 0th left sample and first == 16, 
or addr points to 0th right sample and first == 0. In both cases, step 
== 32.

Step == 32 means that you have to move right by 32 bits (4 bytes) to go 
to the next sample in this channel.

For non-interleaved audio, for each area, addr points to the beginning 
of the 0th sample in the corresponding channel, first == 0 and step == 16.

You just have to pass the area corresponding to the correct channel, and 
the sample index to the function you quoted, and get the address of that 
sample.

So the things are in fact very simple :)

-- 
Alexander E. Patrakov
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

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

* Re: PCM Plugin Channel question
  2014-07-02 13:51     ` Alexander E. Patrakov
@ 2014-07-02 13:57       ` Brandon Yates
  0 siblings, 0 replies; 5+ messages in thread
From: Brandon Yates @ 2014-07-02 13:57 UTC (permalink / raw)
  To: Alexander E. Patrakov; +Cc: alsa-devel

Excellent. The fact that the areas are arrays in the case of multiple channels certainly was the one piece I was missing.  Thanks for the great explanation, you just made my day easier!

-----Original Message-----
From: Alexander E. Patrakov [mailto:patrakov@gmail.com] 
Sent: Wednesday, July 02, 2014 9:51 AM
To: Brandon Yates
Cc: alsa-devel@alsa-project.org
Subject: Re: [alsa-devel] PCM Plugin Channel question

02.07.2014 19:25, Brandon Yates пишет:
> Alex -  thanks. That was helpful. One follow up question.
>
>> if you use the areas-related parameters correctly, the plugin will
> also work with planar or complex layouts.
>
>
> I am not sure if I'm using snd_pcm_channel_area_t correctly. I don't 
> really understand all the fields.  For 1 channel setup I stole the 
> following function from the speex plugin
>
> static inline void *area_addr(const snd_pcm_channel_area_t *area,
> 			      snd_pcm_uframes_t offset)
> {
> 	unsigned int bitofs = area->first + area->step * offset;
> 	return (char *) area->addr + bitofs / 8; }
>
> This works for 1 channel but I don't understand how I would use area 
> for interleaved data.  My thoughts are just take the returned address from
> area_addr then use a for loop separating out odd and even shorts.   Is
> there a better way?

For stereo data, the key thought that you are missing is that there will be in fact _two_ areas for stereo data: area[0] and area[1]. Similarly for 4-channel data: 4 areas. One area per channel.

So, assuming interleaved stereo S16 audio, you will get the following two areas:

In area[0], addr points to the 0th left sample, first == 0, step == 32.
In area[1], either addr points to the 0th left sample and first == 16, or addr points to 0th right sample and first == 0. In both cases, step == 32.

Step == 32 means that you have to move right by 32 bits (4 bytes) to go to the next sample in this channel.

For non-interleaved audio, for each area, addr points to the beginning of the 0th sample in the corresponding channel, first == 0 and step == 16.

You just have to pass the area corresponding to the correct channel, and the sample index to the function you quoted, and get the address of that sample.

So the things are in fact very simple :)

--
Alexander E. Patrakov
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
http://mailman.alsa-project.org/mailman/listinfo/alsa-devel

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

end of thread, other threads:[~2014-07-02 13:57 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-07-01 22:59 PCM Plugin Channel question Brandon Yates
2014-07-02  3:45 ` Alexander E. Patrakov
2014-07-02 13:25   ` Brandon Yates
2014-07-02 13:51     ` Alexander E. Patrakov
2014-07-02 13:57       ` Brandon Yates

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.