At Thu, 10 Jul 2008 12:19:05 +0200 (CEST), Jaroslav Kysela wrote:
On Thu, 10 Jul 2008, Clemens Ladisch wrote:
Norbert van Bolhuis wrote:
as far as I know: sample format S24_LE is 24bit sample in 4 bytes sample format S24_3LE is 24bit sample in 3 bytes (why else have separate definitions), right ?
Yes.
In the ALSA-LIb example /test/pcm.c however (http://www.alsa-project.org/alsa-doc/alsa-lib/_2test_2pcm_8c-example.html) there is no diff between the 2 sample formats.
That example program uses snd_pcm_format_width() although it should have used snd_pcm_format_physical_width() when calculating memory buffer sizes.
I think that the problem is in wrong area->step calculation in alsa-lib, but I'm still investigating where the real culprit is. The snd_pcm_format_width() is used only for sample filling (which is OK).
I think Clemens is right. The program uses snd_pcm_format_width() wrongly. Also, it won't work properly with strict aliasing...
Untested patch is below.
Takashi -- diff --git a/test/pcm.c b/test/pcm.c index cd29259..ecd0afa 100644 --- a/test/pcm.c +++ b/test/pcm.c @@ -38,7 +38,10 @@ static void generate_sine(const snd_pcm_channel_area_t *areas, unsigned char *samples[channels], *tmp; int steps[channels]; unsigned int chn, byte; - int ires; + union { + int i; + unsigned char c[4]; + } ires; unsigned int maxval = (1 << (snd_pcm_format_width(format) - 1)) - 1; int bps = snd_pcm_format_width(format) / 8; /* bytes per sample */ @@ -59,8 +62,8 @@ static void generate_sine(const snd_pcm_channel_area_t *areas, /* fill the channel areas */ while (count-- > 0) { res = sin(phase) * maxval; - ires = res; - tmp = (unsigned char *)(&ires); + ires.i = res; + tmp = ires.c; for (chn = 0; chn < channels; chn++) { for (byte = 0; byte < (unsigned int)bps; byte++) *(samples[chn] + byte) = tmp[byte]; @@ -868,7 +871,7 @@ int main(int argc, char *argv[]) if (verbose > 0) snd_pcm_dump(handle, output);
- samples = malloc((period_size * channels * snd_pcm_format_width(format)) / 8); + samples = malloc((period_size * channels * snd_pcm_format_physical_width(format)) / 8); if (samples == NULL) { printf("No enough memory\n"); exit(EXIT_FAILURE); @@ -881,8 +884,8 @@ int main(int argc, char *argv[]) } for (chn = 0; chn < channels; chn++) { areas[chn].addr = samples; - areas[chn].first = chn * snd_pcm_format_width(format); - areas[chn].step = channels * snd_pcm_format_width(format); + areas[chn].first = chn * snd_pcm_format_physical_width(format); + areas[chn].step = channels * snd_pcm_format_physical_width(format); }
err = transfer_methods[method].transfer_loop(handle, samples, areas);