[alsa-devel] Understanding _snd_pcm_channel_area Struct (PCM Interface)!
Hi all.
I am a bit confused on what I get with this function. I finished my first project but I did not understand what exactly the
_snd_pcm_channel_area at
http://www.alsa-project.org/alsa-doc/alsa-lib/struct__snd__pcm__channel__are...
does.
There are 3 fields in the documentation.
addr, first and step.
It seems that addr is the memory address of the channel samples... so far so good. The "step" is the distance between 2 sample (but I am not sure) and the least, "first", I could not figure out what does it means.
Could I get some help from here?
Thanks in advanced!
Tks!
-------------------
Guilherme Longo Dept. Eng. da Computação Unaerp
Linux User - #484927
*Before Asking http://www.istf.com.br/?page=perguntas
!- I'd rather die on my feet than live on my knees -!
At Tue, 23 Jun 2009 02:40:35 -0300, Guilherme wrote:
Hi all.
I am a bit confused on what I get with this function. I finished my first project but I did not understand what exactly the
_snd_pcm_channel_area at
http://www.alsa-project.org/alsa-doc/alsa-lib/struct__snd__pcm__channel__are...
does.
There are 3 fields in the documentation.
addr, first and step.
It seems that addr is the memory address of the channel samples... so far so good. The "step" is the distance between 2 sample (but I am not sure) and the least, "first", I could not figure out what does it means.
This information is needed to understand how the multi-channel samples are assigned in a stream. The first is the offset of the channel position to the given addr. The step is the bytes to the next sample of that channel.
For example, suppose you have a 2-channel stereo interleaved stream with 16bit samples. Then you'll have an array of snd_pcm_channel_area with two elements, for left and right channels, containing like
area[0].addr = base_address; addr[0].first = 0; addr[0].step = 4; addr[1].addr = base_address; addr[1].first = 2; addr[1].step = 4;
Both channels share the same base address but have the different "first" offset bytes. The step size is 4 = #chanel * sample-size.
For a non-interleaved stereo stream, it'll look like
addr[0].addr = base_addr_0; addr[0].first = 0; addr[0].step = 2; addr[1].addr = base_addr_1; addr[1].first = 0; addr[1].step = 2;
Thus it looks like two mono streams with 16bit samples.
HTH,
Takashi
Takashi...
The base_address and the step sounds pretty clear to me.... just the offset I could not understand.
What the difference in being .first = 0 or .first = 2??? Could you provide please a more in depth explanation. I tried really hard find this but there is nothing related in the documentation.
area[0].addr = base_address; addr[0].first = 0; addr[0].step = 4; addr[1].addr = base_address; addr[1].first = 2; addr[1].step = 4;
P.S. being a stereo or a mono pipeline I understand... just the way the offset works that is not so clear to me.
Thanks in advanced!
Tks!
-------------------
Guilherme Longo Dept. Eng. da Computação Unaerp
Linux User - #484927
*Before Asking http://www.istf.com.br/?page=perguntas
!- I'd rather die on my feet than live on my knees -!
Takashi Iwai wrote:
At Tue, 23 Jun 2009 02:40:35 -0300, Guilherme wrote:
Hi all.
I am a bit confused on what I get with this function. I finished my first project but I did not understand what exactly the
_snd_pcm_channel_area at
http://www.alsa-project.org/alsa-doc/alsa-lib/struct__snd__pcm__channel__are...
does.
There are 3 fields in the documentation.
addr, first and step.
It seems that addr is the memory address of the channel samples... so far so good. The "step" is the distance between 2 sample (but I am not sure) and the least, "first", I could not figure out what does it means.
This information is needed to understand how the multi-channel samples are assigned in a stream. The first is the offset of the channel position to the given addr. The step is the bytes to the next sample of that channel.
For example, suppose you have a 2-channel stereo interleaved stream with 16bit samples. Then you'll have an array of snd_pcm_channel_area with two elements, for left and right channels, containing like
area[0].addr = base_address; addr[0].first = 0; addr[0].step = 4; addr[1].addr = base_address; addr[1].first = 2; addr[1].step = 4;
Both channels share the same base address but have the different "first" offset bytes. The step size is 4 = #chanel * sample-size.
For a non-interleaved stereo stream, it'll look like
addr[0].addr = base_addr_0; addr[0].first = 0; addr[0].step = 2; addr[1].addr = base_addr_1; addr[1].first = 0; addr[1].step = 2;
Thus it looks like two mono streams with 16bit samples.
HTH,
Takashi
At Fri, 26 Jun 2009 23:56:43 -0300, Guilherme wrote:
Takashi...
The base_address and the step sounds pretty clear to me.... just the offset I could not understand.
What the difference in being .first = 0 or .first = 2??? Could you provide please a more in depth explanation. I tried really hard find this but there is nothing related in the documentation.
area[0].addr = base_address; addr[0].first = 0; addr[0].step = 4; addr[1].addr = base_address; addr[1].first = 2; addr[1].step = 4;
P.S. being a stereo or a mono pipeline I understand... just the way the offset works that is not so clear to me.
Actually, the non-interleaved formats can be represented also with a single base_address (and is so in the actual implementation).
addr[0].addr = base_addr; addr[0].first = 0; addr[0].step = 2; addr[1].addr = base_addr; addr[1].first = mono_buffer_len; addr[1].step = 2; addr[2].addr = base_addr; addr[2].first = mono_buffer_len * 2; addr[2].step = 2; ...
The "first" is the offset of the first sample. The address of the first sample of the channel is simply calculated as addr + first. This is because just we want to keep the base address same to all channels as much as possible especially in mmap mode.
Takashi
Tks takashi....
The doubt comes from this block of code:
for (chn = 0; chn < channels; chn++) { if ((areas[chn].first % 8) != 0) { printf("areas[%i].first == %i, abortando...\n", chn, areas[chn].first); exit(EXIT_FAILURE); } //pega endereço e offset da area samples[chn] = /*(signed short *)*/(((unsigned char *)areas[chn].addr) + (areas[chn].first / 8));
if ((areas[chn].step % 16) != 0) { printf("areas[%i].step == %i, aborting...\n", chn, areas[chn].step); exit(EXIT_FAILURE); }
steps[chn] = areas[chn].step / 8; samples[chn] += offset * steps[chn]; }
first:
areas[chn].first % 8 ( I am using chn = 1). So for the only area that I have, if I get the value of the parameter 'first' isn't divisible by 8, the program exits. The same doubt happens with "areas[chn].step % 16" and "areas[chn].step / 8".
This is the parameter I am using:
static snd_pcm_format_t format = SND_PCM_FORMAT_S16; //sample format unsigned 16 bit endian
Perhaps with this practical example I can understand better.
Thanks for ur patient!
Tks!
-------------------
Guilherme Longo
Dept. Eng. da Computação Unaerp
Linux User - #484927
*Before Asking http://www.istf.com.br/?page=perguntas
!- I'd rather die on my feet than live on my knees -!
Takashi Iwai wrote:
At Fri, 26 Jun 2009 23:56:43 -0300, Guilherme wrote:
Takashi...
The base_address and the step sounds pretty clear to me.... just the offset I could not understand.
What the difference in being .first = 0 or .first = 2??? Could you provide please a more in depth explanation. I tried really hard find this but there is nothing related in the documentation.
area[0].addr = base_address; addr[0].first = 0; addr[0].step = 4; addr[1].addr = base_address; addr[1].first = 2; addr[1].step = 4;
P.S. being a stereo or a mono pipeline I understand... just the way the offset works that is not so clear to me.
Actually, the non-interleaved formats can be represented also with a single base_address (and is so in the actual implementation).
addr[0].addr = base_addr; addr[0].first = 0; addr[0].step = 2; addr[1].addr = base_addr; addr[1].first = mono_buffer_len; addr[1].step = 2; addr[2].addr = base_addr; addr[2].first = mono_buffer_len * 2; addr[2].step = 2; ...
The "first" is the offset of the first sample. The address of the first sample of the channel is simply calculated as addr + first. This is because just we want to keep the base address same to all channels as much as possible especially in mmap mode.
Takashi
At Tue, 30 Jun 2009 11:40:20 -0300, Guilherme wrote:
Tks takashi....
The doubt comes from this block of code:
for (chn = 0; chn < channels; chn++) { if ((areas[chn].first % 8) != 0) { printf("areas[%i].first == %i, abortando...\n", chn, areas[chn].first); exit(EXIT_FAILURE); } //pega endereço e offset da area samples[chn] = /*(signed short *)*/(((unsigned char *)areas[chn].addr) + (areas[chn].first / 8));
if ((areas[chn].step % 16) != 0) { printf("areas[%i].step == %i, aborting...\n", chn,
areas[chn].step); exit(EXIT_FAILURE); }
steps[chn] = areas[chn].step / 8; samples[chn] += offset * steps[chn]; }
first:
areas[chn].first % 8 ( I am using chn = 1). So for the only area that I have, if I get the value of the parameter 'first' isn't divisible by 8, the program exits. The same doubt happens with "areas[chn].step % 16" and "areas[chn].step / 8".
This is the parameter I am using:
static snd_pcm_format_t format = SND_PCM_FORMAT_S16; //sample format unsigned 16 bit endian
Perhaps with this practical example I can understand better.
Oops, I wrote wrongly. The first and step fields are not in bytes but bits. That's why 8 and 16 appear there, corresponding to 1 byte and 2 bytes.
Takashi
Hum...
so .. the code
if ((areas[chn].step % 16) !=0 )
is because a 16bits format's been used.
If I wanted a 32bits sample format I should change that for if ((areas[chn].step % 32) !=0 ) ??
and the offset for the first doen's need any changes, is it?
Just a opinion about all this, I think that alsa developers should design graphs for these things, as has in gstreamer documentation. It is a lot easer to understand that way.
It is because I dont understand very well yet, but as I am going to work with sound stuff especially in linux environment, Ill be very soon offering help for this!
;o)
Tks!
-------------------
Guilherme Longo Dept. Eng. da Computação Unaerp
Linux User - #484927
*Before Asking http://www.istf.com.br/?page=perguntas
!- I'd rather die on my feet than live on my knees -!
Takashi Iwai wrote:
At Tue, 30 Jun 2009 11:40:20 -0300, Guilherme wrote:
Tks takashi....
The doubt comes from this block of code:
for (chn = 0; chn < channels; chn++) { if ((areas[chn].first % 8) != 0) { printf("areas[%i].first == %i, abortando...\n", chn, areas[chn].first); exit(EXIT_FAILURE); } //pega endereço e offset da area samples[chn] = /*(signed short *)*/(((unsigned char *)areas[chn].addr) + (areas[chn].first / 8));
if ((areas[chn].step % 16) != 0) { printf("areas[%i].step == %i, aborting...\n", chn,
areas[chn].step); exit(EXIT_FAILURE); }
steps[chn] = areas[chn].step / 8; samples[chn] += offset * steps[chn]; }
first:
areas[chn].first % 8 ( I am using chn = 1). So for the only area that I have, if I get the value of the parameter 'first' isn't divisible by 8, the program exits. The same doubt happens with "areas[chn].step % 16" and "areas[chn].step / 8".
This is the parameter I am using:
static snd_pcm_format_t format = SND_PCM_FORMAT_S16; //sample format unsigned 16 bit endian
Perhaps with this practical example I can understand better.
Oops, I wrote wrongly. The first and step fields are not in bytes but bits. That's why 8 and 16 appear there, corresponding to 1 byte and 2 bytes.
Takashi
At Tue, 30 Jun 2009 12:01:53 -0300, Guilherme wrote:
Hum...
so .. the code
if ((areas[chn].step % 16) !=0 )
is because a 16bits format's been used.
If I wanted a 32bits sample format I should change that for if ((areas[chn].step % 32) !=0 ) ??
Depends.
The step field doesn't specify the sample format. It specifies the bits to the next sample of the given channel.
For such a purpose, checking the sample format bits via snd_pcm_format_width() or snd_pcm_format_physical_width() would be more suitable.
and the offset for the first doen's need any changes, is it?
Just a opinion about all this, I think that alsa developers should design graphs for these things, as has in gstreamer documentation. It is a lot easer to understand that way.
It is because I dont understand very well yet, but as I am going to work with sound stuff especially in linux environment, Ill be very soon offering help for this!
Well, usually you don't have to care about the channel_info. It's just for mmap, and unless you really do want it inevitably, the mmap access isn't needed.
Takashi
participants (2)
-
Guilherme
-
Takashi Iwai