xref: /freebsd-src/tests/sys/sound/pcm_read_write.c (revision e02b579b537998495b06d02be6aa07f03db3a42a)
127ef5d48SFlorian Walpen /*-
227ef5d48SFlorian Walpen  * Copyright (c) 2025 Florian Walpen
327ef5d48SFlorian Walpen  *
427ef5d48SFlorian Walpen  * SPDX-License-Identifier: BSD-2-Clause
527ef5d48SFlorian Walpen  */
627ef5d48SFlorian Walpen 
727ef5d48SFlorian Walpen /*
827ef5d48SFlorian Walpen  * These tests exercise conversion functions of the sound module, used to read
927ef5d48SFlorian Walpen  * pcm samples from a buffer, and write pcm samples to a buffer. The test cases
1027ef5d48SFlorian Walpen  * are non-exhaustive, but should detect systematic errors in conversion of the
1127ef5d48SFlorian Walpen  * various sample formats supported. In particular, the test cases establish
1227ef5d48SFlorian Walpen  * correctness independent of the machine's endianness, making them suitable to
1327ef5d48SFlorian Walpen  * check for architecture-specific problems.
1427ef5d48SFlorian Walpen  */
1527ef5d48SFlorian Walpen 
1627ef5d48SFlorian Walpen #include <sys/types.h>
1727ef5d48SFlorian Walpen #include <sys/soundcard.h>
1827ef5d48SFlorian Walpen 
1927ef5d48SFlorian Walpen #include <atf-c.h>
2027ef5d48SFlorian Walpen #include <stdio.h>
2127ef5d48SFlorian Walpen #include <string.h>
2227ef5d48SFlorian Walpen 
2327ef5d48SFlorian Walpen #include <dev/sound/pcm/sound.h>
2427ef5d48SFlorian Walpen #include <dev/sound/pcm/pcm.h>
2527ef5d48SFlorian Walpen #include <dev/sound/pcm/g711.h>
2627ef5d48SFlorian Walpen 
2727ef5d48SFlorian Walpen /* Generic test data, with buffer content matching the sample values. */
28f6631da0SChristos Margiolis static struct afmt_test_data {
2927ef5d48SFlorian Walpen 	const char *label;
3027ef5d48SFlorian Walpen 	uint8_t buffer[4];
3127ef5d48SFlorian Walpen 	size_t size;
3227ef5d48SFlorian Walpen 	int format;
3327ef5d48SFlorian Walpen 	intpcm_t value;
3427ef5d48SFlorian Walpen 	_Static_assert((sizeof(intpcm_t) == 4),
3527ef5d48SFlorian Walpen 	    "Test data assumes 32bit, adjust negative values to new size.");
36f6631da0SChristos Margiolis } const afmt_tests[] = {
3727ef5d48SFlorian Walpen 	/* 8 bit sample formats. */
3827ef5d48SFlorian Walpen 	{"s8_1", {0x01, 0x00, 0x00, 0x00}, 1, AFMT_S8, 0x00000001},
3927ef5d48SFlorian Walpen 	{"s8_2", {0x81, 0x00, 0x00, 0x00}, 1, AFMT_S8, 0xffffff81},
4027ef5d48SFlorian Walpen 	{"u8_1", {0x01, 0x00, 0x00, 0x00}, 1, AFMT_U8, 0xffffff81},
4127ef5d48SFlorian Walpen 	{"u8_2", {0x81, 0x00, 0x00, 0x00}, 1, AFMT_U8, 0x00000001},
4227ef5d48SFlorian Walpen 
4327ef5d48SFlorian Walpen 	/* 16 bit sample formats. */
4427ef5d48SFlorian Walpen 	{"s16le_1", {0x01, 0x02, 0x00, 0x00}, 2, AFMT_S16_LE, 0x00000201},
4527ef5d48SFlorian Walpen 	{"s16le_2", {0x81, 0x82, 0x00, 0x00}, 2, AFMT_S16_LE, 0xffff8281},
4627ef5d48SFlorian Walpen 	{"s16be_1", {0x01, 0x02, 0x00, 0x00}, 2, AFMT_S16_BE, 0x00000102},
4727ef5d48SFlorian Walpen 	{"s16be_2", {0x81, 0x82, 0x00, 0x00}, 2, AFMT_S16_BE, 0xffff8182},
4827ef5d48SFlorian Walpen 	{"u16le_1", {0x01, 0x02, 0x00, 0x00}, 2, AFMT_U16_LE, 0xffff8201},
4927ef5d48SFlorian Walpen 	{"u16le_2", {0x81, 0x82, 0x00, 0x00}, 2, AFMT_U16_LE, 0x00000281},
5027ef5d48SFlorian Walpen 	{"u16be_1", {0x01, 0x02, 0x00, 0x00}, 2, AFMT_U16_BE, 0xffff8102},
5127ef5d48SFlorian Walpen 	{"u16be_2", {0x81, 0x82, 0x00, 0x00}, 2, AFMT_U16_BE, 0x00000182},
5227ef5d48SFlorian Walpen 
5327ef5d48SFlorian Walpen 	/* 24 bit sample formats. */
5427ef5d48SFlorian Walpen 	{"s24le_1", {0x01, 0x02, 0x03, 0x00}, 3, AFMT_S24_LE, 0x00030201},
5527ef5d48SFlorian Walpen 	{"s24le_2", {0x81, 0x82, 0x83, 0x00}, 3, AFMT_S24_LE, 0xff838281},
5627ef5d48SFlorian Walpen 	{"s24be_1", {0x01, 0x02, 0x03, 0x00}, 3, AFMT_S24_BE, 0x00010203},
5727ef5d48SFlorian Walpen 	{"s24be_2", {0x81, 0x82, 0x83, 0x00}, 3, AFMT_S24_BE, 0xff818283},
5827ef5d48SFlorian Walpen 	{"u24le_1", {0x01, 0x02, 0x03, 0x00}, 3, AFMT_U24_LE, 0xff830201},
5927ef5d48SFlorian Walpen 	{"u24le_2", {0x81, 0x82, 0x83, 0x00}, 3, AFMT_U24_LE, 0x00038281},
6027ef5d48SFlorian Walpen 	{"u24be_1", {0x01, 0x02, 0x03, 0x00}, 3, AFMT_U24_BE, 0xff810203},
6127ef5d48SFlorian Walpen 	{"u24be_2", {0x81, 0x82, 0x83, 0x00}, 3, AFMT_U24_BE, 0x00018283},
6227ef5d48SFlorian Walpen 
6327ef5d48SFlorian Walpen 	/* 32 bit sample formats. */
6427ef5d48SFlorian Walpen 	{"s32le_1", {0x01, 0x02, 0x03, 0x04}, 4, AFMT_S32_LE, 0x04030201},
6527ef5d48SFlorian Walpen 	{"s32le_2", {0x81, 0x82, 0x83, 0x84}, 4, AFMT_S32_LE, 0x84838281},
6627ef5d48SFlorian Walpen 	{"s32be_1", {0x01, 0x02, 0x03, 0x04}, 4, AFMT_S32_BE, 0x01020304},
6727ef5d48SFlorian Walpen 	{"s32be_2", {0x81, 0x82, 0x83, 0x84}, 4, AFMT_S32_BE, 0x81828384},
6827ef5d48SFlorian Walpen 	{"u32le_1", {0x01, 0x02, 0x03, 0x04}, 4, AFMT_U32_LE, 0x84030201},
6927ef5d48SFlorian Walpen 	{"u32le_2", {0x81, 0x82, 0x83, 0x84}, 4, AFMT_U32_LE, 0x04838281},
7027ef5d48SFlorian Walpen 	{"u32be_1", {0x01, 0x02, 0x03, 0x04}, 4, AFMT_U32_BE, 0x81020304},
7127ef5d48SFlorian Walpen 	{"u32be_2", {0x81, 0x82, 0x83, 0x84}, 4, AFMT_U32_BE, 0x01828384},
7227ef5d48SFlorian Walpen 
7327ef5d48SFlorian Walpen 	/* u-law and A-law sample formats. */
7427ef5d48SFlorian Walpen 	{"mulaw_1", {0x01, 0x00, 0x00, 0x00}, 1, AFMT_MU_LAW, 0xffffff87},
7527ef5d48SFlorian Walpen 	{"mulaw_2", {0x81, 0x00, 0x00, 0x00}, 1, AFMT_MU_LAW, 0x00000079},
7627ef5d48SFlorian Walpen 	{"alaw_1", {0x2a, 0x00, 0x00, 0x00}, 1, AFMT_A_LAW, 0xffffff83},
7727ef5d48SFlorian Walpen 	{"alaw_2", {0xab, 0x00, 0x00, 0x00}, 1, AFMT_A_LAW, 0x00000079}
7827ef5d48SFlorian Walpen };
7927ef5d48SFlorian Walpen 
8027ef5d48SFlorian Walpen /* Normalize sample values in strictly correct (but slow) c. */
8127ef5d48SFlorian Walpen static intpcm_t
8227ef5d48SFlorian Walpen local_normalize(intpcm_t value, int val_bits, int norm_bits)
8327ef5d48SFlorian Walpen {
8427ef5d48SFlorian Walpen 	/* Avoid undefined or implementation defined behavior. */
8527ef5d48SFlorian Walpen 	if (val_bits < norm_bits)
8627ef5d48SFlorian Walpen 		/* Multiply instead of left shift (value may be negative). */
8727ef5d48SFlorian Walpen 		return (value * (1 << (norm_bits - val_bits)));
8827ef5d48SFlorian Walpen 	else if (val_bits > norm_bits)
8927ef5d48SFlorian Walpen 		/* Divide instead of right shift (value may be negative). */
9027ef5d48SFlorian Walpen 		return (value / (1 << (val_bits - norm_bits)));
9127ef5d48SFlorian Walpen 	return value;
9227ef5d48SFlorian Walpen }
9327ef5d48SFlorian Walpen 
9427ef5d48SFlorian Walpen /* Restrict magnitude of sample value to 24bit for 32bit calculations. */
9527ef5d48SFlorian Walpen static intpcm_t
9627ef5d48SFlorian Walpen local_calc_limit(intpcm_t value, int val_bits)
9727ef5d48SFlorian Walpen {
98*e02b579bSFlorian Walpen 	/*
99*e02b579bSFlorian Walpen 	 * When intpcm32_t is defined to be 32bit, calculations for mixing and
100*e02b579bSFlorian Walpen 	 * volume changes use 32bit integers instead of 64bit. To get some
101*e02b579bSFlorian Walpen 	 * headroom for calculations, 32bit sample values are restricted to
102*e02b579bSFlorian Walpen 	 * 24bit magnitude in that case. Also avoid implementation defined
103*e02b579bSFlorian Walpen 	 * behavior here.
104*e02b579bSFlorian Walpen 	 */
105*e02b579bSFlorian Walpen 	if (sizeof(intpcm32_t) == (32 / 8) && val_bits == 32)
10627ef5d48SFlorian Walpen 		/* Divide instead of right shift (value may be negative). */
10727ef5d48SFlorian Walpen 		return (value / (1 << 8));
10827ef5d48SFlorian Walpen 	return value;
10927ef5d48SFlorian Walpen }
11027ef5d48SFlorian Walpen 
11127ef5d48SFlorian Walpen /* Lookup tables to read u-law and A-law sample formats. */
11227ef5d48SFlorian Walpen static const uint8_t ulaw_to_u8[G711_TABLE_SIZE] = ULAW_TO_U8;
11327ef5d48SFlorian Walpen static const uint8_t alaw_to_u8[G711_TABLE_SIZE] = ALAW_TO_U8;
11427ef5d48SFlorian Walpen 
11527ef5d48SFlorian Walpen /* Helper function to read one sample value from a buffer. */
11627ef5d48SFlorian Walpen static intpcm_t
11727ef5d48SFlorian Walpen local_pcm_read(uint8_t *src, uint32_t format)
11827ef5d48SFlorian Walpen {
11927ef5d48SFlorian Walpen 	intpcm_t value;
12027ef5d48SFlorian Walpen 
12127ef5d48SFlorian Walpen 	switch (format) {
12227ef5d48SFlorian Walpen 	case AFMT_S8:
12327ef5d48SFlorian Walpen 		value = _PCM_READ_S8_NE(src);
12427ef5d48SFlorian Walpen 		break;
12527ef5d48SFlorian Walpen 	case AFMT_U8:
12627ef5d48SFlorian Walpen 		value = _PCM_READ_U8_NE(src);
12727ef5d48SFlorian Walpen 		break;
12827ef5d48SFlorian Walpen 	case AFMT_S16_LE:
12927ef5d48SFlorian Walpen 		value = _PCM_READ_S16_LE(src);
13027ef5d48SFlorian Walpen 		break;
13127ef5d48SFlorian Walpen 	case AFMT_S16_BE:
13227ef5d48SFlorian Walpen 		value = _PCM_READ_S16_BE(src);
13327ef5d48SFlorian Walpen 		break;
13427ef5d48SFlorian Walpen 	case AFMT_U16_LE:
13527ef5d48SFlorian Walpen 		value = _PCM_READ_U16_LE(src);
13627ef5d48SFlorian Walpen 		break;
13727ef5d48SFlorian Walpen 	case AFMT_U16_BE:
13827ef5d48SFlorian Walpen 		value = _PCM_READ_U16_BE(src);
13927ef5d48SFlorian Walpen 		break;
14027ef5d48SFlorian Walpen 	case AFMT_S24_LE:
14127ef5d48SFlorian Walpen 		value = _PCM_READ_S24_LE(src);
14227ef5d48SFlorian Walpen 		break;
14327ef5d48SFlorian Walpen 	case AFMT_S24_BE:
14427ef5d48SFlorian Walpen 		value = _PCM_READ_S24_BE(src);
14527ef5d48SFlorian Walpen 		break;
14627ef5d48SFlorian Walpen 	case AFMT_U24_LE:
14727ef5d48SFlorian Walpen 		value = _PCM_READ_U24_LE(src);
14827ef5d48SFlorian Walpen 		break;
14927ef5d48SFlorian Walpen 	case AFMT_U24_BE:
15027ef5d48SFlorian Walpen 		value = _PCM_READ_U24_BE(src);
15127ef5d48SFlorian Walpen 		break;
15227ef5d48SFlorian Walpen 	case AFMT_S32_LE:
15327ef5d48SFlorian Walpen 		value = _PCM_READ_S32_LE(src);
15427ef5d48SFlorian Walpen 		break;
15527ef5d48SFlorian Walpen 	case AFMT_S32_BE:
15627ef5d48SFlorian Walpen 		value = _PCM_READ_S32_BE(src);
15727ef5d48SFlorian Walpen 		break;
15827ef5d48SFlorian Walpen 	case AFMT_U32_LE:
15927ef5d48SFlorian Walpen 		value = _PCM_READ_U32_LE(src);
16027ef5d48SFlorian Walpen 		break;
16127ef5d48SFlorian Walpen 	case AFMT_U32_BE:
16227ef5d48SFlorian Walpen 		value = _PCM_READ_U32_BE(src);
16327ef5d48SFlorian Walpen 		break;
16427ef5d48SFlorian Walpen 	case AFMT_MU_LAW:
16527ef5d48SFlorian Walpen 		value = _G711_TO_INTPCM(ulaw_to_u8, *src);
16627ef5d48SFlorian Walpen 		break;
16727ef5d48SFlorian Walpen 	case AFMT_A_LAW:
16827ef5d48SFlorian Walpen 		value = _G711_TO_INTPCM(alaw_to_u8, *src);
16927ef5d48SFlorian Walpen 		break;
17027ef5d48SFlorian Walpen 	default:
17127ef5d48SFlorian Walpen 		value = 0;
17227ef5d48SFlorian Walpen 	}
17327ef5d48SFlorian Walpen 
17427ef5d48SFlorian Walpen 	return (value);
17527ef5d48SFlorian Walpen }
17627ef5d48SFlorian Walpen 
17727ef5d48SFlorian Walpen /* Helper function to read one sample value from a buffer for calculations. */
17827ef5d48SFlorian Walpen static intpcm_t
17927ef5d48SFlorian Walpen local_pcm_read_calc(uint8_t *src, uint32_t format)
18027ef5d48SFlorian Walpen {
18127ef5d48SFlorian Walpen 	intpcm_t value;
18227ef5d48SFlorian Walpen 
18327ef5d48SFlorian Walpen 	switch (format) {
18427ef5d48SFlorian Walpen 	case AFMT_S8:
18527ef5d48SFlorian Walpen 		value = PCM_READ_S8_NE(src);
18627ef5d48SFlorian Walpen 		break;
18727ef5d48SFlorian Walpen 	case AFMT_U8:
18827ef5d48SFlorian Walpen 		value = PCM_READ_U8_NE(src);
18927ef5d48SFlorian Walpen 		break;
19027ef5d48SFlorian Walpen 	case AFMT_S16_LE:
19127ef5d48SFlorian Walpen 		value = PCM_READ_S16_LE(src);
19227ef5d48SFlorian Walpen 		break;
19327ef5d48SFlorian Walpen 	case AFMT_S16_BE:
19427ef5d48SFlorian Walpen 		value = PCM_READ_S16_BE(src);
19527ef5d48SFlorian Walpen 		break;
19627ef5d48SFlorian Walpen 	case AFMT_U16_LE:
19727ef5d48SFlorian Walpen 		value = PCM_READ_U16_LE(src);
19827ef5d48SFlorian Walpen 		break;
19927ef5d48SFlorian Walpen 	case AFMT_U16_BE:
20027ef5d48SFlorian Walpen 		value = PCM_READ_U16_BE(src);
20127ef5d48SFlorian Walpen 		break;
20227ef5d48SFlorian Walpen 	case AFMT_S24_LE:
20327ef5d48SFlorian Walpen 		value = PCM_READ_S24_LE(src);
20427ef5d48SFlorian Walpen 		break;
20527ef5d48SFlorian Walpen 	case AFMT_S24_BE:
20627ef5d48SFlorian Walpen 		value = PCM_READ_S24_BE(src);
20727ef5d48SFlorian Walpen 		break;
20827ef5d48SFlorian Walpen 	case AFMT_U24_LE:
20927ef5d48SFlorian Walpen 		value = PCM_READ_U24_LE(src);
21027ef5d48SFlorian Walpen 		break;
21127ef5d48SFlorian Walpen 	case AFMT_U24_BE:
21227ef5d48SFlorian Walpen 		value = PCM_READ_U24_BE(src);
21327ef5d48SFlorian Walpen 		break;
21427ef5d48SFlorian Walpen 	case AFMT_S32_LE:
21527ef5d48SFlorian Walpen 		value = PCM_READ_S32_LE(src);
21627ef5d48SFlorian Walpen 		break;
21727ef5d48SFlorian Walpen 	case AFMT_S32_BE:
21827ef5d48SFlorian Walpen 		value = PCM_READ_S32_BE(src);
21927ef5d48SFlorian Walpen 		break;
22027ef5d48SFlorian Walpen 	case AFMT_U32_LE:
22127ef5d48SFlorian Walpen 		value = PCM_READ_U32_LE(src);
22227ef5d48SFlorian Walpen 		break;
22327ef5d48SFlorian Walpen 	case AFMT_U32_BE:
22427ef5d48SFlorian Walpen 		value = PCM_READ_U32_BE(src);
22527ef5d48SFlorian Walpen 		break;
22627ef5d48SFlorian Walpen 	case AFMT_MU_LAW:
22727ef5d48SFlorian Walpen 		value = _G711_TO_INTPCM(ulaw_to_u8, *src);
22827ef5d48SFlorian Walpen 		break;
22927ef5d48SFlorian Walpen 	case AFMT_A_LAW:
23027ef5d48SFlorian Walpen 		value = _G711_TO_INTPCM(alaw_to_u8, *src);
23127ef5d48SFlorian Walpen 		break;
23227ef5d48SFlorian Walpen 	default:
23327ef5d48SFlorian Walpen 		value = 0;
23427ef5d48SFlorian Walpen 	}
23527ef5d48SFlorian Walpen 
23627ef5d48SFlorian Walpen 	return (value);
23727ef5d48SFlorian Walpen }
23827ef5d48SFlorian Walpen 
23927ef5d48SFlorian Walpen /* Helper function to read one normalized sample from a buffer. */
24027ef5d48SFlorian Walpen static intpcm_t
24127ef5d48SFlorian Walpen local_pcm_read_norm(uint8_t *src, uint32_t format)
24227ef5d48SFlorian Walpen {
24327ef5d48SFlorian Walpen 	intpcm_t value;
24427ef5d48SFlorian Walpen 
24527ef5d48SFlorian Walpen 	value = local_pcm_read(src, format);
24627ef5d48SFlorian Walpen 	value <<= (32 - AFMT_BIT(format));
24727ef5d48SFlorian Walpen 	return (value);
24827ef5d48SFlorian Walpen }
24927ef5d48SFlorian Walpen 
25027ef5d48SFlorian Walpen /* Lookup tables to write u-law and A-law sample formats. */
25127ef5d48SFlorian Walpen static const uint8_t u8_to_ulaw[G711_TABLE_SIZE] = U8_TO_ULAW;
25227ef5d48SFlorian Walpen static const uint8_t u8_to_alaw[G711_TABLE_SIZE] = U8_TO_ALAW;
25327ef5d48SFlorian Walpen 
25427ef5d48SFlorian Walpen /* Helper function to write one sample value to a buffer. */
25527ef5d48SFlorian Walpen static void
25627ef5d48SFlorian Walpen local_pcm_write(uint8_t *dst, intpcm_t value, uint32_t format)
25727ef5d48SFlorian Walpen {
25827ef5d48SFlorian Walpen 	switch (format) {
25927ef5d48SFlorian Walpen 	case AFMT_S8:
26027ef5d48SFlorian Walpen 		_PCM_WRITE_S8_NE(dst, value);
26127ef5d48SFlorian Walpen 		break;
26227ef5d48SFlorian Walpen 	case AFMT_U8:
26327ef5d48SFlorian Walpen 		_PCM_WRITE_U8_NE(dst, value);
26427ef5d48SFlorian Walpen 		break;
26527ef5d48SFlorian Walpen 	case AFMT_S16_LE:
26627ef5d48SFlorian Walpen 		_PCM_WRITE_S16_LE(dst, value);
26727ef5d48SFlorian Walpen 		break;
26827ef5d48SFlorian Walpen 	case AFMT_S16_BE:
26927ef5d48SFlorian Walpen 		_PCM_WRITE_S16_BE(dst, value);
27027ef5d48SFlorian Walpen 		break;
27127ef5d48SFlorian Walpen 	case AFMT_U16_LE:
27227ef5d48SFlorian Walpen 		_PCM_WRITE_U16_LE(dst, value);
27327ef5d48SFlorian Walpen 		break;
27427ef5d48SFlorian Walpen 	case AFMT_U16_BE:
27527ef5d48SFlorian Walpen 		_PCM_WRITE_U16_BE(dst, value);
27627ef5d48SFlorian Walpen 		break;
27727ef5d48SFlorian Walpen 	case AFMT_S24_LE:
27827ef5d48SFlorian Walpen 		_PCM_WRITE_S24_LE(dst, value);
27927ef5d48SFlorian Walpen 		break;
28027ef5d48SFlorian Walpen 	case AFMT_S24_BE:
28127ef5d48SFlorian Walpen 		_PCM_WRITE_S24_BE(dst, value);
28227ef5d48SFlorian Walpen 		break;
28327ef5d48SFlorian Walpen 	case AFMT_U24_LE:
28427ef5d48SFlorian Walpen 		_PCM_WRITE_U24_LE(dst, value);
28527ef5d48SFlorian Walpen 		break;
28627ef5d48SFlorian Walpen 	case AFMT_U24_BE:
28727ef5d48SFlorian Walpen 		_PCM_WRITE_U24_BE(dst, value);
28827ef5d48SFlorian Walpen 		break;
28927ef5d48SFlorian Walpen 	case AFMT_S32_LE:
29027ef5d48SFlorian Walpen 		_PCM_WRITE_S32_LE(dst, value);
29127ef5d48SFlorian Walpen 		break;
29227ef5d48SFlorian Walpen 	case AFMT_S32_BE:
29327ef5d48SFlorian Walpen 		_PCM_WRITE_S32_BE(dst, value);
29427ef5d48SFlorian Walpen 		break;
29527ef5d48SFlorian Walpen 	case AFMT_U32_LE:
29627ef5d48SFlorian Walpen 		_PCM_WRITE_U32_LE(dst, value);
29727ef5d48SFlorian Walpen 		break;
29827ef5d48SFlorian Walpen 	case AFMT_U32_BE:
29927ef5d48SFlorian Walpen 		_PCM_WRITE_U32_BE(dst, value);
30027ef5d48SFlorian Walpen 		break;
30127ef5d48SFlorian Walpen 	case AFMT_MU_LAW:
30227ef5d48SFlorian Walpen 		*dst = _INTPCM_TO_G711(u8_to_ulaw, value);
30327ef5d48SFlorian Walpen 		break;
30427ef5d48SFlorian Walpen 	case AFMT_A_LAW:
30527ef5d48SFlorian Walpen 		*dst = _INTPCM_TO_G711(u8_to_alaw, value);
30627ef5d48SFlorian Walpen 		break;
30727ef5d48SFlorian Walpen 	default:
30827ef5d48SFlorian Walpen 		value = 0;
30927ef5d48SFlorian Walpen 	}
31027ef5d48SFlorian Walpen }
31127ef5d48SFlorian Walpen 
31227ef5d48SFlorian Walpen /* Helper function to write one calculation sample value to a buffer. */
31327ef5d48SFlorian Walpen static void
31427ef5d48SFlorian Walpen local_pcm_write_calc(uint8_t *dst, intpcm_t value, uint32_t format)
31527ef5d48SFlorian Walpen {
31627ef5d48SFlorian Walpen 	switch (format) {
31727ef5d48SFlorian Walpen 	case AFMT_S8:
31827ef5d48SFlorian Walpen 		PCM_WRITE_S8_NE(dst, value);
31927ef5d48SFlorian Walpen 		break;
32027ef5d48SFlorian Walpen 	case AFMT_U8:
32127ef5d48SFlorian Walpen 		PCM_WRITE_U8_NE(dst, value);
32227ef5d48SFlorian Walpen 		break;
32327ef5d48SFlorian Walpen 	case AFMT_S16_LE:
32427ef5d48SFlorian Walpen 		PCM_WRITE_S16_LE(dst, value);
32527ef5d48SFlorian Walpen 		break;
32627ef5d48SFlorian Walpen 	case AFMT_S16_BE:
32727ef5d48SFlorian Walpen 		PCM_WRITE_S16_BE(dst, value);
32827ef5d48SFlorian Walpen 		break;
32927ef5d48SFlorian Walpen 	case AFMT_U16_LE:
33027ef5d48SFlorian Walpen 		PCM_WRITE_U16_LE(dst, value);
33127ef5d48SFlorian Walpen 		break;
33227ef5d48SFlorian Walpen 	case AFMT_U16_BE:
33327ef5d48SFlorian Walpen 		PCM_WRITE_U16_BE(dst, value);
33427ef5d48SFlorian Walpen 		break;
33527ef5d48SFlorian Walpen 	case AFMT_S24_LE:
33627ef5d48SFlorian Walpen 		PCM_WRITE_S24_LE(dst, value);
33727ef5d48SFlorian Walpen 		break;
33827ef5d48SFlorian Walpen 	case AFMT_S24_BE:
33927ef5d48SFlorian Walpen 		PCM_WRITE_S24_BE(dst, value);
34027ef5d48SFlorian Walpen 		break;
34127ef5d48SFlorian Walpen 	case AFMT_U24_LE:
34227ef5d48SFlorian Walpen 		PCM_WRITE_U24_LE(dst, value);
34327ef5d48SFlorian Walpen 		break;
34427ef5d48SFlorian Walpen 	case AFMT_U24_BE:
34527ef5d48SFlorian Walpen 		PCM_WRITE_U24_BE(dst, value);
34627ef5d48SFlorian Walpen 		break;
34727ef5d48SFlorian Walpen 	case AFMT_S32_LE:
34827ef5d48SFlorian Walpen 		PCM_WRITE_S32_LE(dst, value);
34927ef5d48SFlorian Walpen 		break;
35027ef5d48SFlorian Walpen 	case AFMT_S32_BE:
35127ef5d48SFlorian Walpen 		PCM_WRITE_S32_BE(dst, value);
35227ef5d48SFlorian Walpen 		break;
35327ef5d48SFlorian Walpen 	case AFMT_U32_LE:
35427ef5d48SFlorian Walpen 		PCM_WRITE_U32_LE(dst, value);
35527ef5d48SFlorian Walpen 		break;
35627ef5d48SFlorian Walpen 	case AFMT_U32_BE:
35727ef5d48SFlorian Walpen 		PCM_WRITE_U32_BE(dst, value);
35827ef5d48SFlorian Walpen 		break;
35927ef5d48SFlorian Walpen 	case AFMT_MU_LAW:
36027ef5d48SFlorian Walpen 		*dst = _INTPCM_TO_G711(u8_to_ulaw, value);
36127ef5d48SFlorian Walpen 		break;
36227ef5d48SFlorian Walpen 	case AFMT_A_LAW:
36327ef5d48SFlorian Walpen 		*dst = _INTPCM_TO_G711(u8_to_alaw, value);
36427ef5d48SFlorian Walpen 		break;
36527ef5d48SFlorian Walpen 	default:
36627ef5d48SFlorian Walpen 		value = 0;
36727ef5d48SFlorian Walpen 	}
36827ef5d48SFlorian Walpen }
36927ef5d48SFlorian Walpen 
37027ef5d48SFlorian Walpen /* Helper function to write one normalized sample to a buffer. */
37127ef5d48SFlorian Walpen static void
37227ef5d48SFlorian Walpen local_pcm_write_norm(uint8_t *dst, intpcm_t value, uint32_t format)
37327ef5d48SFlorian Walpen {
37427ef5d48SFlorian Walpen 	local_pcm_write(dst, value >> (32 - AFMT_BIT(format)), format);
37527ef5d48SFlorian Walpen }
37627ef5d48SFlorian Walpen 
37727ef5d48SFlorian Walpen ATF_TC(pcm_read);
37827ef5d48SFlorian Walpen ATF_TC_HEAD(pcm_read, tc)
37927ef5d48SFlorian Walpen {
38027ef5d48SFlorian Walpen 	atf_tc_set_md_var(tc, "descr",
38127ef5d48SFlorian Walpen 	    "Read and verify different pcm sample formats.");
38227ef5d48SFlorian Walpen }
38327ef5d48SFlorian Walpen ATF_TC_BODY(pcm_read, tc)
38427ef5d48SFlorian Walpen {
38527ef5d48SFlorian Walpen 	const struct afmt_test_data *test;
38627ef5d48SFlorian Walpen 	uint8_t src[4];
38727ef5d48SFlorian Walpen 	intpcm_t expected, result;
38827ef5d48SFlorian Walpen 	size_t i;
38927ef5d48SFlorian Walpen 
39027ef5d48SFlorian Walpen 	for (i = 0; i < nitems(afmt_tests); i++) {
39127ef5d48SFlorian Walpen 		test = &afmt_tests[i];
39227ef5d48SFlorian Walpen 
39327ef5d48SFlorian Walpen 		/* Copy byte representation, fill with distinctive pattern. */
39427ef5d48SFlorian Walpen 		memset(src, 0x66, sizeof(src));
39527ef5d48SFlorian Walpen 		memcpy(src, test->buffer, test->size);
39627ef5d48SFlorian Walpen 
39727ef5d48SFlorian Walpen 		/* Read sample at format magnitude. */
39827ef5d48SFlorian Walpen 		expected = test->value;
39927ef5d48SFlorian Walpen 		result = local_pcm_read(src, test->format);
40027ef5d48SFlorian Walpen 		ATF_CHECK_MSG(result == expected,
40127ef5d48SFlorian Walpen 		    "pcm_read[\"%s\"].value: expected=0x%08x, result=0x%08x",
40227ef5d48SFlorian Walpen 		    test->label, expected, result);
40327ef5d48SFlorian Walpen 
40427ef5d48SFlorian Walpen 		/* Read sample at format magnitude, for calculations. */
40527ef5d48SFlorian Walpen 		expected = local_calc_limit(test->value, test->size * 8);
40627ef5d48SFlorian Walpen 		result = local_pcm_read_calc(src, test->format);
40727ef5d48SFlorian Walpen 		ATF_CHECK_MSG(result == expected,
40827ef5d48SFlorian Walpen 		    "pcm_read[\"%s\"].calc: expected=0x%08x, result=0x%08x",
40927ef5d48SFlorian Walpen 		    test->label, expected, result);
41027ef5d48SFlorian Walpen 
41127ef5d48SFlorian Walpen 		/* Read sample at full 32 bit magnitude. */
41227ef5d48SFlorian Walpen 		expected = local_normalize(test->value, test->size * 8, 32);
41327ef5d48SFlorian Walpen 		result = local_pcm_read_norm(src, test->format);
41427ef5d48SFlorian Walpen 		ATF_CHECK_MSG(result == expected,
41527ef5d48SFlorian Walpen 		    "pcm_read[\"%s\"].norm: expected=0x%08x, result=0x%08x",
41627ef5d48SFlorian Walpen 		    test->label, expected, result);
41727ef5d48SFlorian Walpen 	}
41827ef5d48SFlorian Walpen }
41927ef5d48SFlorian Walpen 
42027ef5d48SFlorian Walpen ATF_TC(pcm_write);
42127ef5d48SFlorian Walpen ATF_TC_HEAD(pcm_write, tc)
42227ef5d48SFlorian Walpen {
42327ef5d48SFlorian Walpen 	atf_tc_set_md_var(tc, "descr",
42427ef5d48SFlorian Walpen 	    "Write and verify different pcm sample formats.");
42527ef5d48SFlorian Walpen }
42627ef5d48SFlorian Walpen ATF_TC_BODY(pcm_write, tc)
42727ef5d48SFlorian Walpen {
42827ef5d48SFlorian Walpen 	const struct afmt_test_data *test;
42927ef5d48SFlorian Walpen 	uint8_t expected[4];
43027ef5d48SFlorian Walpen 	uint8_t dst[4];
43127ef5d48SFlorian Walpen 	intpcm_t value;
43227ef5d48SFlorian Walpen 	size_t i;
43327ef5d48SFlorian Walpen 
43427ef5d48SFlorian Walpen 	for (i = 0; i < nitems(afmt_tests); i++) {
43527ef5d48SFlorian Walpen 		test = &afmt_tests[i];
43627ef5d48SFlorian Walpen 
43727ef5d48SFlorian Walpen 		/* Write sample of format specific magnitude. */
43827ef5d48SFlorian Walpen 		memcpy(expected, test->buffer, sizeof(expected));
43927ef5d48SFlorian Walpen 		memset(dst, 0x00, sizeof(dst));
44027ef5d48SFlorian Walpen 		value = test->value;
44127ef5d48SFlorian Walpen 		local_pcm_write(dst, value, test->format);
44227ef5d48SFlorian Walpen 		ATF_CHECK_MSG(memcmp(dst, expected, sizeof(dst)) == 0,
44327ef5d48SFlorian Walpen 		    "pcm_write[\"%s\"].value: "
44427ef5d48SFlorian Walpen 		    "expected={0x%02x, 0x%02x, 0x%02x, 0x%02x}, "
44527ef5d48SFlorian Walpen 		    "result={0x%02x, 0x%02x, 0x%02x, 0x%02x}, ", test->label,
44627ef5d48SFlorian Walpen 		    expected[0], expected[1], expected[2], expected[3],
44727ef5d48SFlorian Walpen 		    dst[0], dst[1], dst[2], dst[3]);
44827ef5d48SFlorian Walpen 
44927ef5d48SFlorian Walpen 		/* Write sample of format specific, calculation magnitude. */
45027ef5d48SFlorian Walpen 		memcpy(expected, test->buffer, sizeof(expected));
45127ef5d48SFlorian Walpen 		memset(dst, 0x00, sizeof(dst));
45227ef5d48SFlorian Walpen 		value = local_calc_limit(test->value, test->size * 8);
45327ef5d48SFlorian Walpen 		if (value != test->value) {
45427ef5d48SFlorian Walpen 			/*
45527ef5d48SFlorian Walpen 			 * 32 bit sample was reduced to 24 bit resolution
45627ef5d48SFlorian Walpen 			 * for calculation, least significant byte is lost.
45727ef5d48SFlorian Walpen 			 */
45827ef5d48SFlorian Walpen 			if (test->format & AFMT_BIGENDIAN)
45927ef5d48SFlorian Walpen 				expected[3] = 0x00;
46027ef5d48SFlorian Walpen 			else
46127ef5d48SFlorian Walpen 				expected[0] = 0x00;
46227ef5d48SFlorian Walpen 		}
46327ef5d48SFlorian Walpen 		local_pcm_write_calc(dst, value, test->format);
46427ef5d48SFlorian Walpen 		ATF_CHECK_MSG(memcmp(dst, expected, sizeof(dst)) == 0,
465*e02b579bSFlorian Walpen 		    "pcm_write[\"%s\"].calc: "
46627ef5d48SFlorian Walpen 		    "expected={0x%02x, 0x%02x, 0x%02x, 0x%02x}, "
46727ef5d48SFlorian Walpen 		    "result={0x%02x, 0x%02x, 0x%02x, 0x%02x}, ", test->label,
46827ef5d48SFlorian Walpen 		    expected[0], expected[1], expected[2], expected[3],
46927ef5d48SFlorian Walpen 		    dst[0], dst[1], dst[2], dst[3]);
47027ef5d48SFlorian Walpen 
47127ef5d48SFlorian Walpen 		/* Write normalized sample of full 32 bit magnitude. */
47227ef5d48SFlorian Walpen 		memcpy(expected, test->buffer, sizeof(expected));
47327ef5d48SFlorian Walpen 		memset(dst, 0x00, sizeof(dst));
47427ef5d48SFlorian Walpen 		value = local_normalize(test->value, test->size * 8, 32);
47527ef5d48SFlorian Walpen 		local_pcm_write_norm(dst, value, test->format);
47627ef5d48SFlorian Walpen 		ATF_CHECK_MSG(memcmp(dst, expected, sizeof(dst)) == 0,
47727ef5d48SFlorian Walpen 		    "pcm_write[\"%s\"].norm: "
47827ef5d48SFlorian Walpen 		    "expected={0x%02x, 0x%02x, 0x%02x, 0x%02x}, "
47927ef5d48SFlorian Walpen 		    "result={0x%02x, 0x%02x, 0x%02x, 0x%02x}, ", test->label,
48027ef5d48SFlorian Walpen 		    expected[0], expected[1], expected[2], expected[3],
48127ef5d48SFlorian Walpen 		    dst[0], dst[1], dst[2], dst[3]);
48227ef5d48SFlorian Walpen 	}
48327ef5d48SFlorian Walpen }
48427ef5d48SFlorian Walpen 
48527ef5d48SFlorian Walpen ATF_TC(pcm_format_bits);
48627ef5d48SFlorian Walpen ATF_TC_HEAD(pcm_format_bits, tc)
48727ef5d48SFlorian Walpen {
48827ef5d48SFlorian Walpen 	atf_tc_set_md_var(tc, "descr",
48927ef5d48SFlorian Walpen 	    "Verify bit width of different pcm sample formats.");
49027ef5d48SFlorian Walpen }
49127ef5d48SFlorian Walpen ATF_TC_BODY(pcm_format_bits, tc)
49227ef5d48SFlorian Walpen {
49327ef5d48SFlorian Walpen 	const struct afmt_test_data *test;
49427ef5d48SFlorian Walpen 	size_t bits;
49527ef5d48SFlorian Walpen 	size_t i;
49627ef5d48SFlorian Walpen 
49727ef5d48SFlorian Walpen 	for (i = 0; i < nitems(afmt_tests); i++) {
49827ef5d48SFlorian Walpen 		test = &afmt_tests[i];
49927ef5d48SFlorian Walpen 
50027ef5d48SFlorian Walpen 		/* Check bit width determined for given sample format. */
50127ef5d48SFlorian Walpen 		bits = AFMT_BIT(test->format);
50227ef5d48SFlorian Walpen 		ATF_CHECK_MSG(bits == test->size * 8,
50327ef5d48SFlorian Walpen 		    "format_bits[%zu].size: expected=%zu, result=%zu",
50427ef5d48SFlorian Walpen 		    i, test->size * 8, bits);
50527ef5d48SFlorian Walpen 	}
50627ef5d48SFlorian Walpen }
50727ef5d48SFlorian Walpen 
50827ef5d48SFlorian Walpen ATF_TP_ADD_TCS(tp)
50927ef5d48SFlorian Walpen {
51027ef5d48SFlorian Walpen 	ATF_TP_ADD_TC(tp, pcm_read);
51127ef5d48SFlorian Walpen 	ATF_TP_ADD_TC(tp, pcm_write);
51227ef5d48SFlorian Walpen 	ATF_TP_ADD_TC(tp, pcm_format_bits);
51327ef5d48SFlorian Walpen 
51427ef5d48SFlorian Walpen 	return atf_no_error();
51527ef5d48SFlorian Walpen }
516